2016-07-07 3 views
1

In meinem Entwicklungsteam ausgeführt wird, verwenden wir das CQRS Muster wie in this article beschrieben und mit den empfohlen DI Containern: Simple Injector (pun beabsichtigt).Einfache Injector Registrierung und intern Command

Dies ist unsere aktuelle Projektstruktur:

  • 01 WebApp references => [02] [03]
  • 02 Contract
  • 03 BusinessLayer

Projekt 01 ist der Client (eine ASP.NET MVC 4-Anwendung) Wo registrieren wir die Dienste unserer App mit Simple Injector (Bootstrapper). In Projekt 03 werden alle Befehls- und Abfrage-Handler wie im Artikel beschrieben definiert. In Projekt 02 sind die Befehle und Abfragen definiert. Damit Simple Injector die Handler registrieren kann, hat der Client einen direkten Verweis auf die Business-Schicht-Assembly.

Der Behälter registriert die commandhandlers wie diese

container.Register(typeof(ICommandHandler<>), assemblies); 

Das Problem ist jetzt, ist, dass einer unserer Entwickler versehentlich einen seiner Handler-Klassen vergessen wie public zu erklären. Also statt:

public class AddCustomerCommandHandler : ICommandHandler<AddCustomerCommand> { ... } 

schrieb er:

class AddCustomerCommandHandler : ICommandHandler<AddCustomerCommand> { ... } 

nun nach msdn, wenn der Zugriffsmodifikator weggelassen wird, intern verwendet wird:

Klassen und Strukturen, die direkt deklariert werden Innerhalb eines Namespace (in andere Wörter, die nicht in anderen Klassen oder Strukturen verschachtelt sind) kann entweder öffentlich oder intern sein. Intern ist der Standardwert, wenn kein Zugriff Modifikator angegeben ist.

Nun internen ist definiert als:

Der Typ oder Mitglied kann von jedem Code in der gleichen Anordnung zugegriffen werden kann, aber nicht von einer anderen Baugruppe.

Nach dem Versuch, diesen Befehl auszuführen, wirft die Laufzeit keine Fehler und der Befehl wird glücklich ausgeführt. Ich bin überrascht, weil ich einen Simulationsfehler von Simple Injector erwarten würde, was nicht der Fall ist. Auch wenn ich versuche, das Handler-Objekt direkt aus dem Client zu instantiieren, gibt der Compiler mir einen Fehler, it cannot access an internal class here, wie beabsichtigt! Warum kann Simple Injector diesen Commandhandler registrieren, während sein Zugriffsmodifikator internal ist?

Antwort

2

In vorherigen Versionen übersprang die Batch-Registrierung des Simple Injectors standardmäßig interne Typen, und mit einem Flag konnten Sie auch interne Typen registrieren.

Diese Methode hat sich als problematisch erwiesen, da in einigen Anwendungen die fehlenden Typen es ermöglichten, dass die Anwendung weiter ausgeführt wurde und gleichzeitig ein fehlerhaftes Verhalten angezeigt wurde (und somit nicht ordnungsgemäß ausgeführt wurde).

Um dies zu verhindern, haben wir dieses Verhalten geändert und nun sehen Sie immer, dass dieser Typ ebenfalls registriert wird. Die Idee ist, dass ein erwarteter Typ lautlos übergangen wird. Da die meisten Anwendungen vollständig vertrauenswürdig ausgeführt werden, können interne Typen erstellt und aufgelöst werden. Aus der Sicht des einfachen Injektors ist es also in Ordnung, wenn ein Typ intern ist. Bei anderen Anwendungstypen erkennt ein Aufruf von Verify schnell einen unstrukturierbaren Typ.

Auch aus Sicht einer Anwendung sollte es kein Problem für den Typ sein, intern zu sein, da die Verbraucher mit der öffentlichen Schnittstelle sprechen, die dieser Typ implementiert.

Der Grund, warum dies in Ihrem Fall fehlschlägt, liegt wahrscheinlich daran, dass Sie Ihre Handler versenden und dynamic während des Versands eingeben. Was Sie sehen, ist IMO eine Eigenart in der C# dynamischen Infrastruktur. C# versucht, Ihre Handle-Methode mithilfe der Reflektion zu finden, aber die Handle-Methode ist intern, da der Typ der Umgebung intern ist. Diese Methode kann nicht gefunden werden, obwohl der Typ eine öffentliche Schnittstelle implementiert, die diese Methode enthält. Dies ist eine Eigenart und ich glaube, dass C# diese Methode immer noch finden sollte; aber das tut es nicht. Aus diesem Grund schlägt Ihr Code fehl.

Sie können mehrere Dinge tun, um solche Probleme in Zukunft zu vermeiden. Sie können beispielsweise einen Komponententest definieren, der prüft, ob alle Handler öffentlich sind. Oder Sie können eine spezielle generische -und public-Wrapper-Klasse mit einem Handler als Konstruktorargument definieren und diesen Wrapper anstelle des Handlers auflösen. Sie können dynamisches Tippen für diesen Wrapper verwenden. Oder Sie registrieren einen äußersten Dekorator, den Sie sicherstellen, dass er öffentlich ist. C# spiegelt den äußersten Typ wider, so dass dies funktioniert.

Sie können auch die Überprüfung in Simple Injector integrieren, wo Sie den äußersten Decorator bedingt registrieren, und das Prädikat eine Ausnahme auslösen lassen, falls der Handler intern ist.

Verwandte Themen