Contextual Binding mit Ninject

Im einem meiner letzten Beitrag habe ich Ninject vorgestellt und eine grobe Einweisung gegeben, wie man DI auf Grundlage des kleinen, kostenlosen Frameworks realisieren kann.

An dieser Stelle möchte ich noch ein fortgeschrittenes Thema von Ninject erläutern: “Contextual Bindings”, wie der Name bereits erahnen lässt geht es um die Bindungen (oder auch Mappings), das zentrale Konfigurationsmittel, von Ninject. Was mit dem Zusatz Contextual gemeint wird nochmals exemplarisch dargestellt.

 

Was ist Contextual Binding?

Contextual Binding bedeutet, dass man dass Binding oder Mapping auf Grundlage von verschiedenen Bedingungen definiert und dadurch nur eine, wenn auch etwas komplexere Mapping-Klasse benötigt. Es gibt zwei unterschiedliche Arten von Bedingungen, die man mit Ninject verwenden kann:

  • basierend auf eigenen Attributen
  • basierend auf dem Ninject.Tag Attribut

Die Bedingungen werden durch eine Implementierung des Interfaces ICondition<T> dann von Ninject evaluiert. Das Interface ICondition<T> ist zwar in der Ninject.Core.dll enthalten allerdings ist dessen Implementierung, die abstrakte Klasse ConditionBase<T> und die davon abgeleiteten Klassen in der Assembly Ninject.Conditions.dll vorhanden, daher muss man auch diese Bibliothek im Projekt referenzieren.

 

Ein einfaches Beispiel

Das Beispiel aus meinem vorherigen Post werden wir nun einfach um Contextual Binding erweitern.  Die API für das Contextual Binding ist dank der Verwendung von Fluent Interfaces sehr einfach. (Fluent Interfaces habe ich bereits in einem anderem Post erläutert)

Contextual Binding mit eigenen Attributen

Eigene Attribute lassen sich ganz einfach durch vererben von der Klasse System.Attribut realisieren. Für das erste Beispiel benötigen also nur ein neues Attribut

#region Service Types
 
  public class Productive : System.Attribute { }
 
#endregion

 

Bisher sahen die beiden Mapping-Module so aus

#region Ninject Modules
 
public class ProductiveModel : StandardModule
{
    public override void Load()
    {
        Bind<IMediaDevice>().To<WindowsPhone>();
        Bind<IAddress>().To<NationalAddress>();
    }
}
 
public class StagingModule : StandardModule
{
    public override void Load()
    {
        Bind<IMediaDevice>().To<IPhone>();
        Bind<IAddress>().To<InternationalAddress>();
 
    }
}
 
#endregion

 

Der vorletzte Schritt besteht im dekorieren der Customer-Klasse mit dem Productive-Attribut

[Productive]
public class Customer
{
  //...
}

 

Durch die Verwendung von Contextual Bindings kann man das StagingModule an dieser stelle kürzen, so dass nur noch eine Mapping-Modul Klasse benötigt wird.

public class TheOneAndOnlyMappingModule : StandardModule
{
 public override void Load()
 {
   Bind<IMediaDevice>().To<IPhone>();
   Bind<IMediaDevice>().To<WindowsPhone>().
    Only(When.Context.Target.HasAttribute<Productive>());
 
   Bind<IAddress>().To<InternationalAddress>();
   Bind<IAddress>().To<NationalAddress>().
     Only(When.Context.Target.HasAttribute<Productive>());
 }
}

 

Neben der Möglichkeit der Prüfung des Zieles (hier Context.Target. …) gibt es in Ninject noch diverse andere Conditions die man setzen kann. Die Verwendung der Bedingungen ist analog zur Verwendung des hier gezeigten Context.Target.HasAttribute.

 

Contextual Binding mit dem Ninject Tag Attribut

Ninject bringt von Haus aus das Attribut Tag mit, mit dessen Hilfe können ebenfalls Contextual Bindings realisiert werden. Der Tag-Property kann ein beliebiger String-Wert übergeben werden, der dann im Mapping-Modul ausgewertet werden kann.

Die bereits vorhandene Klasse Customer kann demnach auch so aussehen

[Tag("Productive")]
public class Customer
{
 //...
}

 

Auch das Mapping-Modul muss hier nur minimal angepasst werden

 

public class MyTagMappingModule : StandardModule
{
    public override void Load()
    {
        Bind<IMediaDevice>().To<IPhone>();
        Bind<IMediaDevice>().To<WindowsPhone>().
         Only(When.Context.Target.Tag == "Productive");
        Bind<IAddress>().To<InternationalAddress>();
        Bind<IAddress>().To<NationalAddress>().
         Only(When.Context.Target.Tag == "Productive");
    }
}

 

Wie immer gilt auch beim Contextual Binding von Ninject “Alle Wege führen nach Rom”. Erlaubt ist also was gefällt…

 

Fazit

Erst durch die Verwendung von Features wie Contextual Bindings kann man die Fähigkeiten die Ninject bietet ausschöpfen und vom DI-Pattern einen Nutzen schöpfen. Jede Applikation die sich Jenseits von “Hello World” befindet wird wohl einfacher und schneller zu entwickeln und zu testen sein wenn man auf Contextual Bindings zurück greift.

Wer sich allerdings seinen schönen “cleanen” Code nicht noch durch Attribute aufblähen will, die ohne Contextual Bindings nicht existent wären, der kann sich auf den nächsten Ninject-Beitrag über Conventions-Based Binding freuen.

 

Technorati-Tags: ,,
DotNetKicks-DE Image
Published Montag, 25. Januar 2010 22:00 von ThorstenHans
Abgelegt unter: ,

Kommentare

# Twitter Trackbacks for Contextual Binding mit Ninject - .NET rocks [dotnet-forum.de] on Topsy.com

Ping Antwort von  Twitter Trackbacks for                 Contextual Binding mit Ninject - .NET rocks         [dotnet-forum.de]        on Topsy.com

# re: Contextual Binding mit Ninject

Dienstag, 26. Januar 2010 09:59 von Rainer Hilmer

Der Code sieht sehr chic aus (0 WTFs/min). Ich glaube ich muß mir NInject doch einmal näher anschauen. Freue mich schon auf den nächsten Beitrag.

# re: Contextual Binding mit Ninject

Dienstag, 26. Januar 2010 10:20 von ThorstenHans

Ich liebe die WTFs/min Einheit :D

# ConventionBased Binding mit Ninject

Mittwoch, 27. Januar 2010 07:00 von .NET rocks

Nachdem ich bereits das Contextual Binding von Ninject vorgestellt habe, möchte ich an dieser Stelle

# Contextual Bindings mit Ninject

Mittwoch, 27. Januar 2010 10:55 von dotnet-kicks.de

Sie wurden gekickt (eine gute Sache) - Trackback von dotnet-kicks.de

# Dependency Injection mit Ninject

Montag, 15. Februar 2010 08:32 von .NET rocks

Ninject ist ein kleines und doch sehr mächtiges Framework, in einer kurzen Blog Serie zeige ich wie man

Kommentar abgeben

(verpflichtend) 
(verpflichtend) 
(optional)
(verpflichtend)