IOC Container im Vergleich

Überblick

IOC/DI

Welche Container gibt es

Welchen Container wir wirklich verwenden sollten ;-)

Spring.net

DryIOC

Unity

IOC/DI

  • IOC als allgemeiner Überbegriff für eine Umkehr der Verantwortlichkeiten im Programmablauf
    • Programmablauf wird nicht durch Programm selbst gesteuert
    • Eingabe von Werten in Konsole vs. WPF Anwendung
  • DI - Dependency Injection als ein ein kleiner Teil von IOC
    • Einfügen von Abhängigkeiten in eine Komponente damit diese ihre Funktion erfüllen kann.

Best Practices

  • Konstruktor Injection
  • Composition Root
    • d.h. keine Verwendung des Containers außerhalb Composition Root
      • Bsp. Problem: ViewCommands

Welche DI/IOC Container gibt es

  • Spring.net
  • Castle Windsor
  • DryIoc
  • Ninject
  • Structure Map
  • Unity Container
  • Simple IOC
  • AutoFac
  • Caliburn Micro
  • TinyIoc
  • (MEF)
  • ...

Welchen Container wir wirklich verwenden sollten ;-)

depends on ...

Frage 1: Welche Container Funktionalitäten benötige ich in der aktuellen Komponente?
Frage 2: Welcher Container liefert die benötigten Funktionalitäten?

Beispiel 1 - Desktopanwendung mit DB Zugriff

  • Benötige Funktionen außer DI
    • NHibernate
    • Transaction Handling
    • AOP bzw. Querschnittsfunktionen

spring.net oder einen anderen Container mit cooler ORM Integration

Beispiel 2 - Simpler Microservice ohne DB Zugriff und UI

  • Benötigte Fuktionen außer DI
    • MVC Integration
    • evtl. bissl Querschnittsfunktionalität

unity, autofac, ... auf jeden Fall kein Schwergewicht mit 1001 Funktion, die nicht benötigt wird.

Spring.net


  <object id="ContractorCoachingViewModel"
          type="Com.QueoFlow.TrackingtoolLogistik.WPF.Ui.UserControls.ContractorCoaching.ViewModels.ContractorCoachingViewModel, TrackingtoolLogistik.WPF"
          singleton="false">
    <property name="ProjectService"
              ref="projectService" />
    <property name="OrderImportService"
              ref="orderImportService" />
    <property name="ProjectReportService"
              ref="projectReportService" />
    <property name="SpecialPeriodService"
              ref="specialPeriodService" />

Instanzen über Namen erstellen


public T Create<T>(params object[] arguments) where T : class {
    IApplicationContext context = ContextRegistry.GetContext();
    string typeName = typeof(T).Name;
    typeName = typeName.Substring(0, 1).ToLower() + typeName.Substring(1);
    T viewModel;
    if (arguments.Length > 0) {
        viewModel = context.GetObject(typeName, arguments) as T;
    } else {
        viewModel = context.GetObject(typeName) as T;
    }
    return viewModel;
}

Unser bisheriger Standardcontainer mit sehr guter NHibernate Integration und Transaction Management sowie sehr umfargreichen AOP Möglichkeiten.

Vorteile

  • Sehr gute Verknüpfung von NHibernate und Transactions
  • Gewachsene interne Bibliotheken zur Nutzung in Tests, Basisklassen usw.
  • Gute Integration von Konfigurationsmöglichkeiten wie Properties Dateien
  • XML Konfiguration und somit z.B. Möglichkeiten einzelne Werte über Platzhalter zu injecten
  • Tonnenweise Doku

Nachteile

  • Standardmäßig über XML Konfiguriert und somit schlecht wartbar
  • Träges Startverhalten
  • Teils schlechte Performance beim Auflösen vieler Elemente
  • Gefühlt keine Relevanz in der Menge der IOC Container
  • Wahrscheinlich keine Weiterentwicklung außerhalb des normalen .net Frameworkes. Also kein Xamarin, .netCore usw.

DryIoc


var c = new Container();
c.Register<IClient, SomeClient>();
c.Register<IService, SomeService>();

// somewhere else
IClient client = c.Resolve<IClient>();

Ein sehr schneller Container, der teilweise in WPF Anwendungen eingesetzt wird, wenn keine weitere DB Anbindung notwendig ist und nur simples DI genötigt wird.

Vorteile

  • Sehr schnelle Initialisierung und Auflösung
  • Einfache Konfiguration im Code

Nachteile

  • Keine einfach Möglichkeit z.B. Konfigurationswerte zu injecten.
  • Beim letzten Test noch keine finale WebApi Unterstützung

Unity (1/2)


/* Alle in der Assembly, die ein gleichnamiges Interface haben
 * als transient (neue Instanz pro resolve) 
 * https://msdn.microsoft.com/en-us/library/ff660872(v=pandp.20).aspx
 */
container.RegisterTypes(
    AllClasses.FromAssemblies(typeof(UnityConfig).Assembly),
    WithMappings.FromMatchingInterface,
    WithName.Default, WithLifetime.Transient);

/* Nur einen einzelnen Typ inkl. Interface registrieren */
container.RegisterType<IMainViewModel, MainViewModel>();

/* https://github.com/roblevine/UnityLog4NetExtension */
container.AddNewExtension<Log4NetExtension>();

Etwas schwergewichtigerer Container von MS der in diversen WebApi und WPF Anwendungen eingesetzt, wenn keine weitere DB Anbindung benötigt wird.

Unity (2/2)


/* Resolve from container */                
ISomeService someService = 
        container.Resolve<ISomeService>();

/* Constructor injection */
public SomeClass(ISomeService someService){...}

/* Property injection */
[Dependency]
public ILog Logger { set; protected get; }

Vorteile

  • Schnelle Initialisierung und Auflösung
  • Einfache Konfiguration im Code
  • AOP möglich
    
    [AppSettingsDependency("ReadingAnalysis.DecimalPlaces")]
    public int DecimalPlaces { get; set; }
    
  • Integration in Web Api
  • Konfiguration in XML möglich, aber nicht Standard

Nachteile

  • Keine einfach Möglichkeit z.B. Konfigurationswerte zu injecten.

Alles klar?

Wiki Stichwort: DI-/IOC Container