2016-08-08 26 views
0

Ich habe Zweifel, da ich neu in der Abhängigkeit und IoC bin.Wie bekomme ich DbContext in verschachtelten Methoden mit SimpleInjector

Ich habe eine Domain-Schicht (mit Geschäftslogik) und eine Datenschicht. Wir implementieren keine Repositories, wir verwenden EF Core direkt. Es ist ein Klassenbibliothek Projekt, wir verwenden es in einer AspNetCore Web API, WinForms und in einem anderen Framework.

Die Idee ist, den gleichen Kontext innerhalb eines Bereichs zu verwenden.

Das Problem ist, dass ich nicht in der Lage bin, den gleichen Kontext in der geschachtelten Methodenausführung zu bekommen. Ich bin mir sicher, weil ich das Konzept nicht vollständig verstanden habe. Kannst du mir dabei helfen?

Beispiel:

public class MyTest 
{ 
    public void TestContainer() 
    { 
     var parentContext = MyContainer.Container.GetInstance<MyContext>(); 
     TestParentAndChildContext(parentContext); 
    } 

    private void TestParentAndChildContext(MyContext parentContext) 
    { 
     var childContext = MyContainer.Container.GetInstance<MyContext>(); 
     Assert.AreEqual(parentContext, childContext); 
    } 
} 

public class MyContainer 
{ 
    public static Container Container 
    { 
     get { return container ?? (container = RegisterAndVerifyContainer()); } 
    } 

    private static Container RegisterAndVerifyContainer() 
    { 
     var container = new Container(); 
     container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle(); 
     container.Register<DbContext, MyContext>(Lifestyle.Scoped); 

     container.Verify(); 

     return container; 
    } 
} 

Antwort

0

In der Einfachen Injector Sie eine Implementierung durch seine Abstraktion registrieren. In Ihrem Fall haben Sie einen MyContext durch seinen Basistyp DbContext registriert. Von diesem Punkt an wird Simple Injector wissen, dass es einen MyContext konstruieren muss, falls jemand nach einem DbContext fragt. Dies ist der ganze Zweck des

Programms auf eine Schnittstelle, nicht eine Implementierung

In Ihrem Fall jedoch, obwohl Sie die MyContext durch ihre Abstraktion zu tun registrieren, erhalten Sie eine neue Instanz von MyContext fordern direkt, anstatt es durch seine Abstraktion anzufordern. Dies bewirkt, dass der einfache Injektor in seiner Liste registrierter Abstraktionen nach dem MyContext sucht. Da es keine Registrierung für MyContext gibt (es gibt zwar DbContext, aber das ist ein ganz anderer Typ, was Simple Injector betrifft), wird Simple Injector versuchen, die fehlende Registrierung hinzuzufügen. Dies ist erfolgreich, da MyContext konkret ist und einen einzelnen auflösbaren Konstruktor hat. Standardmäßig löst Simple Injector nicht registrierte Betonarten als Transient auf.

So wird MyContext als transient aufgelöst, wenn direkt angefordert. Sie können dieses Problem lösen, indem Sie Ihre Test auf die folgende Veränderung:

public void TestContainer() 
{ 
    using (MyContainer.Container.BeginExecutionContextScope()) { 
     var parentContext = MyContainer.Container.GetInstance<DbContext>(); 
     TestParentAndChildContext(parentContext); 
    } 
} 

private void TestParentAndChildContext(MyContext parentContext) 
{ 
    var childContext = MyContainer.Container.GetInstance<DbContext>(); 
    Assert.AreEqual(parentContext, childContext); 
} 

dass einfache Injector in der Regel beachten Sie, diese Art von Fehler erkennt. Wenn Sie MyContext von seinem Basistyp DbContext registrieren, aber MyContext direkt in einen Konstruktor eines Typs injizieren, wird Simple Injector einen Short Circuited Dependency Fehler beim Aufruf Verify() auslösen.

Der Grund, warum Sie nicht davor gewarnt wurden, ist, dass Sie Verify() vor der Auflösungsaktion aufgerufen haben (normalerweise sollten Sie GetInstance nicht in Ihrer Anwendung aufrufen; stattdessen sollten Sie alle Objektgraphen im Voraus erstellen). Aber wenn man Verify nennen würde (wieder) nach MyContext Lösung würden Sie die Ausnahme sehen Aufspringen:

[TestMethod] 
public void TestContainer() 
{ 
    var container = MyContainer.Container.GetInstance<DbContext>(); 
    var parentContext = container.GetInstance<MyContext>(); 
    var childContext = container.GetInstance<MyContext>(); 

    // This call will fail 
    container.Verify(); 
} 
+0

Vielen Dank für Ihr Wissen zu teilen. – Lucas

+0

Vielen Dank für Ihr Wissen. Ich habe noch viel zu lernen, was würdest du sagen, es ist die beste Option in meinem Fall? Ich habe beschränkten Zugriff auf die Präsentationsschicht, wir arbeiten unter der Business-Schicht und der Datenschicht und müssen denselben Kontext teilen, während wir einige Geschäftsregeln ausführen. Alle Projekte sind Klassenbibliotheken. Wie könnte ich GetInstance nicht von meiner Geschäftslogik aus aufrufen und die Graphen vorher aufbauen? – Lucas

+0

@Lucus: Sie rufen 'GetInstance' nicht auf. Sie registrieren alle Objekte im Startpfad der Anwendung (Composition Root). Und alle Instanzen werden mithilfe der Konstruktorinjektion empfangen. Sie bauen tiefe Objektgrappen. – Steven