Mehr von Jürgen Gutsch

Mehr von Jürgen Gutsch

Empfehlungen von Jürgen Gutsch

Blog-Empfehlungen von Jürgen Gutsch

Willkommen bei ASP.NET Zone. Anmelden | Registrieren | Hilfe

Jürgen Gutsch

ASP.NET und mehr...

News

  • It's like a whiteboard with super powers: Taskplanung mal anders mit Trello
Dependency Injection, ASP.NET MVC 4 und Autofac

In annähernd jedem Projekt nutze ich seit 2008 Dependency Injection (DI) um Komponenten und Module lose zu koppeln, die Nutzung zu Vereinfachen und vor allem, um die Testbarkeit zu gewährleisten.

DI gibt die Abhängigkeiten (Sub-Komponenten) von außen in die Komponente herein, statt innen zu erzeugen. Üblicherweise werden die Abhängigkeiten über den Constructor injiziert, in manchen Szenarien macht auch die Injektion über öffentliche Eigenschaften Sinn.

Beispiel abhängige Komponenten:

public class DataRepo
{
    public void SaveMyData(IEntity data) {}
}

public class BusinessService
{
    private readonly DataRepo _repo;
    public BusinessService()
    {
        _ repo = new DataRepo();
    }
}

In diesem Szenario kann die Komponente BusinessService nicht isoliert ohne das DataRepository getestet werden. Möglicherweise hat das DataRepository weitere Abhängigkeiten an eine Datenbank, was die Sache dann noch schwieriger macht.

Die Lösung bietet die Entkopplung der Komponenten:

public interface IDataRepo
{
    void SaveMyData(IEntity data);
}

public class DataRepo : IDataRepo
{
    public void SaveMyData(IEntity data) {}
}

public class BusinessService
{
    private readonly DataRepo _repo;
    public BusinessService(IDataRepo repo)
    {
        _ repo = repo;
    }
}

Nun kann ich die Instanz des DataRepository von außen hineingeben:

var repo = new DataRepository();
var service = new BusinessService(repo);

Im Falle eines UnitTest, kann ich eine Simulation eines Repository hineingeben, das Testdaten liefert oder so tut als würde es Daten speichern können.

IoC-Container

IoC-Container sind Werkzeuge, die einem das instanziieren der Objekte abnehmen, deren Lebenszeit verwalten können und in der Regel das hineingeben (injizieren) von Abhängigkeiten abnehmen. Alle IoC-Container machen das fast auf die gleiche Weise, mal mit etwas mehr, mal mit etwas weniger zusätzlicher Unterstützung.

Im Grunde wird einem IoC-Container immer nur mitgeteilt, für welches Interface er welche konkrete Klasse instanziieren und hineingeben kann. Dabei werden für die zu instanziierenden Klassen wieder die Abhängigkeiten aufgelöst und hineingegeben.

Mehr zu IoC-Container hat Peter Bucher in folgenden Beiträgen geschrieben:

Autofac

Autofac ist ein Leichtgewichtiger IoC-Container der unter anderem diverse Unterstützung für ASP.NET (Webforms, MVC3, MVC4 und Web API), MVC, MEF und SignalR bietet. Das Framework wird als Open Source auf Google Code gehostet. Autofac und die einzelnen Unterstützenden Bibliotheken können auch per NuGet in die Projekte integriert werden:
http://nuget.org/packages?q=Autofac

DI mit MVC

Hier möchte ich kurz vorstellen wie Autofac als DIIoCContainer in ASP.NET MVC4 genutzt werden kann, um Abhängigkeiten in Controllern und sogar in AktionFiltern aufzulösen.

Als ersten Schritt wird analog zu den anderen MVC Konfigurationen eine Klasse IocConfig im Verzeichnis App_Start angelegt. die dann ebenso in der Global.asax.cs aufgerufen wird.

public static void RegisterDependencies()
{
    var currentAssembly = typeof(MvcApplication).Assembly;

    var builder = new ContainerBuilder();

    builder.RegisterControllers(currentAssembly);
    builder.RegisterModelBinders(currentAssembly);
    builder.RegisterModelBinderProvider();
    builder.RegisterFilterProvider();
    builder.RegisterModule(new AutofacWebTypesModule());

    builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
    builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork));

    var container = builder.Build();

    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}

Nach der Instanziierung des ContainerBuilder sehen wir hier die MVC4 Integration von Autofac:

  • RegisterControllers holt automatisch alle Controller aus der angegebenen Assembly und registriert sie im ContainerBuilder
  • RegisterModelBinders macht das wie RegisterControllers nur für ModelBinder
  • RegisterModelBinderProvider registriert den AutofacModelBinderProvider, eine Autofac Implementation des IModelBinderProvider
  • RegisterFilterProvider ermöglicht das injizieren von Abhängigkeiten in eigene ActionFilter
  • Als letztes in diesem Block sehen wir die Registrierung eines Moduls, welches die MVC spezifischen HTTP-Abstraktionen im ContainerBilder registriert, um diese automatisch in die Komponenten hineinzugeben.

In den nächsten zwei Zeilen sehen wir die Typische Registrierung von Mappings zwischen Interface und konkreten Klassen. In der ersten Zeile die Registrierung von generischen Typen die in meinem Fall sehr nützlich ist um mit einer Registrierung sechs bis sieben Daten-Repositories zu erschlagen.

Zuletzt wird der Container gebaut und dem AutofacDependencyResolver hinzugefügt, der wiederum als DepencyResolver dem ASP.NET MVC4 hinzugefügt wird.

Wer’s nicht glaubt, kann es gerne selber asuprobieren, aber das wars tatsächlich schon fast ;-)

Nun kann der MVC Controller einfach mit einem oder mehreren Constructor Parametern ausgestattet werden und wir können mit den injizierten Instanzen arbeiten als hätten wir sie selber erstellt:

public class HomeController : Controller
{
    private readonly IUnitOfWork _unitOfWork;
    public HomeController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
[...]
}

Weitere IoC-Container

In den nächsten Beiträgen zeige ich die Konfiguration von folgenden weiteren IoC-Containern anhand des selben Szenarios

  • LightCore
  • Unity
  • NInject
  • StructureMap
  • Castle Windsor

[Update]

Auf Anfrage eines Lesers nehme ich noch StructureMap in die Liste mit auf und erweitere dann auch gerne um Castle Windsor. Ich muss allerdings dazu sagen, dass ich selber StructureMap und Castle Windsor nie selber verwendet habe und ich mich erst etwas einlesen muss.

Der genannte Leser würde hier im Blog auch gerne einen Vergleich der Container sehen. Wer noch? Eventuell lasse ich mich ja noch überreden. ;-)

[Update2]

“DI-Container” nach “IoC-Container” geändert. Danke an Laurent Bugnion der mich gestern in seinem Vortrag bei der Zurich Developers .NET User Group daran erinnert hat dass es da einen erheblichen Unterschied in der Definition gibt ;-)

Posted: Dienstag, 5. Februar 2013 09:55 von Jürgen Gutsch
Abgelegt unter: , , ,

Kommentare

Peter Bucher sagte:

Ich will einen Vergleich :)

# Februar 5, 2013 16:18

Jürgen Gutsch sagte:

Irgendwie dachte ich mir das schon, Peter :-)

# Februar 6, 2013 10:22

Jürgen Gutsch sagte:

Einleitung Eine Einführung in die Problematik und einen kurzen Überblick über IoC-Container habe ich

# März 18, 2013 22:06
Anonyme Kommentare sind nicht zugelassen