Patterns und Practices für die Softwareentwicklung in .NET: die Enterprise Library. Teil 2: Unity und der Service Locator

Patterns und Practices für die Softwareentwicklung in .NET: die Enterprise Library. Teil 2: Unity und der Service Locator

“Für viele Vorgänge, welche man tagtäglich in der .NET Entwicklung benötigt gibt es bereits viele hilfreiche Libraries. In dieser Serie werden best practices vom Patterns&Practices Team vorgestellt. Alle diese Beiträge können durch den Tag “p&p” abgerufen werden.”

Wie bereits im ersten Post versprochen wird auf das vorher erstellte Beispiel ein Service Locator aufgesetzt. Hierfür wird ServiceLocation vom Pattern&Practices Team verwendet, welches Unity verwenden kann. Doch was genau macht ein ServiceLocator und wozu verwendet man diesen?

Die durch Dependency Injection erreichte loskoppelung muss natürlich “irgendwie” adressierbar bleiben. Hierfür schaltet man oft einen Service Locator dazwischen, welcher es uns nun ermöglicht ein Service anhand eines gewissen Typen (Interfaces) ausfindig zu machen. Dieser Servicelocator fungiert als zentrale Registrierung für Services, welche die Anwendung verwendet. Ein wichtiger Vorteil des ServiceLocators ist es, dass Codeteile einfacher zum Testen sind. Man holt sich nur das Interface, nicht jedoch das konkrete Service – Unity kümmert sich um die richtige Auflösung. Services können, da zu jedem Service im Normallfall ein Interface existiert, einfach gemockt werden. Somit kann man eine Implementierung flexibel austauschen, ohne das die Anwendung selbst etwas davon mitbekommt – ein “new” fällt also weg. In der unten dargestellten Abbildung ist ein solcher Vorgang dargestellt. Hierbei wird der Zugriff auf einen Webdienst abstrahiert. die Anwendung (als Business Application bezeichnet) holt sich in diesem Fall den Webservicezugriff. Die Anwendung weis jedoch nicht über die Klasse “WebServiceImpl” bescheid. Dies könnte auch “WebServiceImplMock” sein. Der ServiceLocator liefert das eigentliche Interface zurück.

20101123_Pic1

Doch wie sieht dies jetzt im Quellcode aus? Nehmen wir mal an, wir wollen die Klasse “IApplicationPageService” aus unserem letzten Beispiel verwenden. Hierfür würde man NICHT so vorgehen:

 IApplicationPageService service = new ApplicationPageService();

Damit hätten wir wieder eine Abhängigkeit auf die konkrete Implementierung und diese müssten wir, sollte eine neue Implementierung, z.B. “FastApplicationPageService” eingebaut werden, überall austauschen. Dies macht keinen Sinn. Im Normalfall ist die konkrete Implementierung gar im Using – in der Anwendung muss ich mir darüber schlichtweg keine Gedanken machen. Mit einem Service Locator sieht es nun folgendermaßen aus:

 var pagesvc = ServiceLocator.Current.GetInstance<IApplicationPageService>();

Wie man hier sieht, es wird kein “new” verwendet. In unserem Fall würde Unity darüber entscheiden ob ein “new” im Hintergrund verwendet wird oder das Service als Singleton zurück geliefert wird. Wie dies unterschieden wird habe ich bereits im ersten Beitrag (Konfiguration) erklärt. Dies macht die Anwendung wesentlich flexibler als bisher. Was noch notwendig ist, bevor man den ServiceLocator verwenden kann ist dessen Assoziierung mit Unity sowie die Referenzierung der Library notwendig. ServiceLocation ist in “Microsoft.Practices.ServiceLocation” enthalten:

20101123_Pic2

Die Integration mit Unity erfolgt folgendermaßen:

 UnityServiceLocator loc = new UnityServiceLocator(myContainer);
ServiceLocator.SetLocatorProvider(() => loc);

Wer sich jetzt wundert wo “ServiceLocator” herkommt: ist statisch ;). Viel Spaß mit Service Location!

Referenzen:

Service Locator: https://martinfowler.com/articles/injection.html#UsingAServiceLocator