Einfacher Injektor: Gleiche UnitOfWork-Instanz über Dienste desselben Graphen injizieren

8

Ich habe mehrere Dienste, von denen jeder UnitOfWork in den Konstruktor unter Verwendung des einfachen Injektors IoC-Containers injiziert hat.

>

Momentan kann ich sehen, dass jede UnitOfWork -Instanz ein separates Objekt ist, das ist schlecht, da ich Entity Framework verwende und dieselbe Kontextreferenz für alle Arbeitseinheiten benötige.

Wie kann ich sicherstellen, dass dieselbe UnitOfWork -Instanz in alle Services für jede Auflösungsanforderung eingefügt wird? Mein UnitOfWor wird nach Abschluss des Befehls von einem externen Command-Handler-Decorator gespeichert.

Bitte beachten Sie, dies ist eine allgemeine Bibliothek und wird sowohl für MVC als auch für Windows Forms verwendet. Es wäre schön, wenn möglich eine generische Lösung für beide Plattformen zu haben.

Code ist unten:

%Vor%

Das gewünschte Ergebnis der unteren Zeile besteht darin, ein Objekt mit einer gemeinsamen UnitOfWork-Instanz im gesamten erstellten Objektgraphen zu erstellen:

%Vor%

Hier sind meine Dienste:

%Vor%     
g18c 08.06.2012, 19:38
quelle

1 Antwort

20

Welche Registrierung Sie benötigen, hängt von der Art der Anwendung ab. Da Sie über zwei verschiedene Frameworks sprechen (MVC und WinForms), haben beide eine andere Registrierung.

Für eine MVC-Anwendung (oder Webanwendungen im Allgemeinen) ist es am häufigsten, die Arbeitseinheit auf einem pro Webanfrage . Bei der folgenden Registrierung wird beispielsweise die Arbeitseinheit während einer einzelnen Webanforderung zwischengespeichert:

%Vor%

Der Nachteil dieser Registrierung besteht darin, dass die Arbeitseinheit nicht entsorgt wird (falls erforderlich). Es gibt ein Erweiterungspaket für Der Simple Injector, der dem Container RegisterPerWebRequest Erweiterungs-Methoden hinzufügt. Dadurch wird automatisch sichergestellt, dass die Instanz am Ende der Web-Anfrage platziert wird. Mit diesem Paket können Sie folgende Registrierung durchführen:

%Vor%

Was ist eine Verknüpfung zu:

%Vor%

Eine Windows Forms-Anwendung dagegen ist in der Regel ein einzelner Thread (ein einzelner Benutzer wird diese Anwendung verwenden). Ich glaube, dass es nicht ungewöhnlich ist, eine einzige Arbeitseinheit pro Formular zu haben, die die Form geschlossen hat, aber mit dem Befehl / Handler-Muster denke ich, ist es besser, einen serviceorientierten Ansatz zu nehmen. Was ich damit meine ist, dass es gut wäre, es so zu gestalten, dass Sie die Business-Schicht in einen WCF-Dienst verschieben können, ohne Änderungen an der Präsentationsebene vornehmen zu müssen. Sie können dies erreichen, indem Sie Ihre Befehle nur Primitive und (andere) DTO enthalten . Speichern Sie daher Entity Framework-Entitäten nicht in Ihren Befehlen, da dies die Serialisierung des Befehls erheblich erschwert und später zu Überraschungen führt.

Wenn Sie dies tun, wäre es praktisch, eine neue Arbeitseinheit zu erstellen, bevor der Command-Handler startet, dieselbe Arbeitseinheit während der Ausführung dieses Handlers wieder verwendet und sie festschreibt, wenn der Handler erfolgreich beendet wurde (und immer Entsorgen Sie es). Dies ist ein typisches Szenario für die Per Lifetime Scope Lebensstil . Es gibt ein Erweiterungspaket Fügt dem Container RegisterLifetimeScope Erweiterungsmethoden hinzu. Mit diesem Paket können Sie folgende Registrierung durchführen:

%Vor%

Was ist eine Verknüpfung zu:

%Vor%

Die Registrierung ist jedoch nur die Hälfte der Geschichte. Der zweite Teil besteht darin, zu entscheiden, wann die Änderungen der Arbeitseinheit gespeichert werden sollen, und im Falle der Verwendung des Lifetime Scope-Lebensstils, wo ein solcher Bereich gestartet und beendet wird. Da Sie vor der Ausführung des Befehls explizit einen Gültigkeitszeitraum für die Gültigkeitsdauer starten sollten und ihn beenden sollen, wenn der Befehl ausgeführt wurde, verwenden Sie am besten einen Befehlshandler-Decorator, der die Befehlsroutinen umbrechen kann. Daher würden Sie normalerweise für die Formularanwendung einen zusätzlichen Befehlshandler-Decorator registrieren, der den Lebensdauerumfang verwaltet. Dieser Ansatz funktioniert in diesem Fall nicht. Schau dir den folgenden Dekorateur an, aber beachte bitte, dass es falsch ist :

%Vor%

Dieser Ansatz funktioniert nicht , weil der verzierte Befehlshandler erstellt wird, bevor der Gültigkeitsbereich für den Gültigkeitszeitraum gestartet wird.

Wir könnten versucht sein, dieses Problem wie folgt zu lösen, aber das stimmt auch nicht:

%Vor%

Obwohl ein ICommandHandler<T> im Kontext eines lebenslangen Bereichs angefordert wird, wird tatsächlich ein IUnitOfWork für diesen Bereich injiziert, der Container gibt einen Handler zurück, der (wieder) mit einem LifetimeScopeCommandHandlerDecorator<T> versehen ist. Der Aufruf von handler.Handle(command) wird daher zu einem rekursiven Aufruf führen, und wir werden mit einer Stapelüberlauf-Ausnahme enden.

Das Problem besteht darin, dass das Abhängigkeitsdiagramm bereits erstellt wurde, bevor wir den Lebensdauerumfang starten können. Wir müssen daher den Abhängigkeitsgraphen aufbrechen, indem wir den Rest des Graphen verzögern. Der beste Weg, dies zu tun, damit Sie Ihr Anwendungsdesign sauber halten können, besteht darin, den Decorator in einen Proxy zu verwandeln und eine Factory in ihn einzufügen, die den Typ erzeugt, den er umbrechen sollte.Solch LifetimeScopeCommandHandlerProxy<T> wird wie folgt aussehen:

%Vor%

Indem wir einen Delegaten injizieren, können wir die Zeit, in der die Instanz erstellt wird, verzögern und dadurch die Konstruktion des Restdiagramms verzögern. Der Trick besteht nun darin, diese Proxy-Klasse so zu registrieren, dass sie die umhüllten Instanzen einschleusen wird, anstatt sich (natürlich) erneut zu injizieren. Simple Injector unterstützt das Einfügen von Func<T> factories in Decorators. Sie können also einfach RegisterDecorator und in diesem Fall sogar die RegisterSingleDecorator Erweiterungsmethode verwenden.

Beachten Sie, dass die Reihenfolge, in der Decorators (und dieser Proxy) registriert sind (offensichtlich) wichtig ist. Da dieser Proxy einen neuen lebenslangen Gültigkeitsbereich startet, sollte er den Decorator umbrechen, der die Arbeitseinheit festlegt. Mit anderen Worten, eine vollständigere Registrierung würde so aussehen:

%Vor%

Die umgekehrte Registrierung von Proxy und Decorator würde bedeuten, dass das TransactionCommandHandlerDecorator<T> von einem anderen IUnitOfWork abhängig wäre als der Rest des Abhängigkeitsdiagramms, was bedeuten würde, dass alle Änderungen an der Arbeitseinheit vorgenommen werden Grafik wird nicht übergeben. Mit anderen Worten, Ihre Anwendung wird nicht mehr funktionieren. Überprüfen Sie diese Registrierung daher immer sorgfältig.

Viel Glück.

    
Steven 09.06.2012, 14:55
quelle