HowTo: Alle Implementationen vom Interface X über Castle Windsor per DI auflösen

image

Der Titel klingt recht "kompliziert”, ist es aber eigentlich gar nicht. Grundproblem: Wir haben ein Interface und mehrere Implementationen davon. In unserer Applikation wollen diese über Konstruktor-Injektion holen und nacheinander aufrufen. Mit dem ArrayResolver und Castle Windsor dies sehr einfach zu bewerkstelligen. Der Blogpost darf auch als “realer” Einstieg in das Thema Dependency Injection angesehen werden.

Grundlagen

Einen kleinen Einstieg hab ich hier bereits gegeben. In meinem Beispiel nutze ich Castle Windsor, genauso gut hätte ich wahrscheinlich ein anderes DI Framework nehmen können.

Benötigte Assemblies

image

Der Download von Castle Windsor kann erstmal etwas erschreckend sein. Benötigt werden diese 4 Dlls (Core/DynamicProxy2/MicroKernel/Windsor).

 

Mein (reales) Beispiel

Wir haben bei uns eine Applikation die auf einige Backend Systeme zugreift. Da die Backend Systeme ab und an “einschlafen” haben wir ein “WakeUpTool” geschrieben, welches nach einem bestimmten Intervall die Systeme auf Stand-by hält.

Wir haben bei uns ein “IWakeUpCommand” mit der simplen Methode “WakeUp”. Pro Backendsystem gibt es eine Implementation davon. Die einzelnen Aufwach-Befehle können völlig getrennt voneinander agieren. Wichtig ist nur, dass immer alle geladen werden.
Da es sein kann, dass nun noch ein weiteres Backend System dazu kommt (oder eins wegfällt), wollten wir die Verbindung zwischen ApplicationRunner und den einzelnen Commands so lose wie möglich gestalten.

Fake Beispiel

image In meinem Beispiel, welches ihr ganz unten auch runterladen könnt, wird einfach nur ein ConsoleWriteLine ausgegeben.

In dem Beispiel gibt es das Interface “ICommand” mit der Methode “Exceute” und 3 Implementationen.

 

Das Interface “IApplicationRunner” beinhaltet nur eine “Run” Methode. Dies ist mein eigentlicher Eintrittspunkt in die Applikationslogik.

Beispiel Command:

namespace CastleWindsorFindAllImplementations.Commands
{
    public class WakeUpCommand : ICommand
    {
        public void Execute()
        {
            Console.WriteLine("WakeUpCommand");
        }
    }
}

Der ApplicationRunner nimmt einfach ein Array an ICommands entgegen und ruft diese nacheinander auf. Keine große Magie.

namespace CastleWindsorFindAllImplementations
{
    public class ApplicationRunner : IApplicationRunner
    {
        private ICommand[] _commands;

        public ApplicationRunner(ICommand[] commands)
        {
            this._commands = commands;
        }

        public void Run()
        {
            foreach (ICommand command in _commands)
            {
                command.Execute();
            }
        }
    }
}

Castle Windsor Magie – wie der ApplicationRunner zu den Implementationen kommt!

Ganz am Anfang registrieren wir einen ArrayResolver für Windsor Castle. Nur damit kann unser “container” auch Arrays auflösen.

Die Zeile 7 erspart eine Menge tipparbeit. Damit wird dem Container (so wie ich es verstanden habe ;) ) gesagt, dass er alle Interfaces suchen soll und dazu die passenden Implementationen registrieren soll. Suchen soll er zudem nur in dieser Assembly. Nur durch diesen Automatismus ist es auch erst elegant, weil man so einfach nur eine neuen Command hinzufügen muss und das Framework kümmert sich um die Auflösung. Man muss kein Setup etc. anpassen. Sehr praktisch, aber sicherlich wird es auch zu Problemen führen wenn es komplexer wird.

In Zeile 10 holen wir uns über den “container” unseren IApplicationRunner und sagen dann einfach nur “Run”. Windsor Castle hat als einzige Implementation unsere “ApplicationRunner” Klasse gefunden. Diese wiederrum braucht ein Array aus ICommands. Voodoo :)

    class Program
    {
        static void Main(string[] args)
        {
            IWindsorContainer container = new WindsorContainer();
            container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));
            container.Register(AllTypes.Pick().FromAssembly(typeof(ApplicationRunner).Assembly)
                    .WithService.FirstInterface());

            IApplicationRunner runner = container.Resolve<IApplicationRunner>();
            runner.Run();

            Console.ReadLine();
        }
    }

Was ist wenn ich einen konkreten Typ von ICommand haben will?

Dann hat man erst mal ein Problem, weil es so nicht vorgesehen ist. Was man machen kann ist bestimmten Komponenten innerhalb des “containers” einen Namen zu geben.

Fazit

Diese Methode ist äußerst praktisch wenn man einfach nur eine Liste von Implementationen nutzen will ohne sie explizit erst zu registrieren. Einen genauen Typen daraus wieder herauszupuzzeln ist allerdings schwieriger.

[ Download Democode ]


Kick It auf dotnet-kicks.de
Wenn dir der Blogpost gefallen hat, dann hinterlasse doch einen Kommentar. Wenn du auf dem Laufenden bleiben willst, abonniere unseren RSS Feed oder folge uns auf Twitter.

About the author

Written by Robert Mühsig

Robert Mühsig (@robert0muehsig) ist Webentwickler und beschäftigt sich mit Web-Frameworks (vor allem dem ASP.NET MVC Framework) und scheut sich auch nicht vor Javascript. Ansonsten bloggt er über all jene Probleme, die ihm über den Weg laufen. Seit 2008 ist er Microsoft MVP für ASP.NET und er arbeitet bei der T-Systems Multimedia Solutions GmbH in Dresden. Treffen kann man ihn online via Twitter (@robert0muehsig) oder dieser Seite oder bei der .NET User Group Dresden.

2 Responses

  1. Top. Danke, auch mal ein Beispiel aus der Praxis zu Interfaces, nicht immer nur “Spiel”-Beispiele.

    Reply

Comment on this post

Letzte Posts

  • Carriage Return / Neue Zeile in Textareas

    Eine kleine Aufgabe: Jede neue Textzeile (Carriage Return/Wenn man Enter drückt ) in einer Textarea soll ein Element in einer Auflistung sein – wie mach ich das jetzt am einfachsten? Eigentlich ein grundlegendes Element im Web und der Nutzer macht bewusst Absätze – daher wäre es nur gerecht, wenn man das auch entsprechend würdigt. Kleine ...

  • image.png
    Doom, Quake, Wolfenstein & co. Source Code auf GitHub

    id Software, die Macher von Doom, Quake, Wolfenstein & co., stellen regelmäßig ihre älteren Spieltitle als Open Source zur Verfügung. Das Ganze runterzuladen fand ich bisher immer recht mühselig, allerdings gibt es seit kurzer Zeit die Sourcen auch auf GitHub. Darunter Spiele wie Doom 3, Quake 3, Wolfenstein für iOS. Wer also schon immer mal ...

  • image.png
    Twitter Bootstrap 2.0 released & “Release Präsentation”

    Wie bereits vom Twitter Bootstrap Team angekündigt wurde offiziel die Version 2.0 des UI Toolskits “Twitter Bootstrap” veröffentlich. Zudem wurden die Slides, welche bei der Release Party gezeigt wurden auch veröffentlicht: Downloads finden sich auf der Twitter Bootstrap Seite auf GitHub. Wenn dir der Blogpost gefallen hat, dann hinterlasse doch einen Kommentar. Wenn du auf ...

  • image.png
    Javascript zu Dart Translator

    Dart, Google Javascript Alternative, wurde vor ein paar Monaten vorgestellt und die Webentwickler Szene ist noch etwas gespalten, ob Dart nun überflüssig ist oder einfach nur cool und längst überfällig ist. Um die Sprache näher zu erläutern hat Google die grundlegenden Javascript Basics nach Dart übersetzt. Das Ergebnis ist der “Translator”. Der Name mag momentan ...

  • Twitter Bootstrap 2.0–“Beta”

    Twitter Bootstrap, ein UI-Toolkit für Web-Applikationen von Twitter, erscheint (wie bereits berichtet) demnächst in der Version 2.0. Der offizielle Release ist am 31. Januar, allerdings beginnt jetzt laut Mark Otto (einer der Hauptentwickler von Twitter Bootstrap) die intensive Test-Phase. Das heisst, das es nun offiziel auch die 2.0 Dokumentation online gibt. Im Vergleich zur aktuellen ...

Support us!

Facebook