简体   繁体   中英

How to get DbContext in nested methods using SimpleInjector

I have a doubt since I'm new to the dependency and IoC.

I have a domain layer (with business logic) and a data layer. We do not implement repositories, we use EF Core directly. It is a Class Library project, we use it in a AspNetCore web api, WinForms and inside another framework.

The idea is to use the same context inside a scope.

The problem is that I'm not being able to get the same context in the nested method execution, I'm sure it is because I did not understand the concept completely, can you guys give me a help on that?

Example:

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;
    }
}

In Simple Injector you register an implementation by its abstraction. In your case you registed an MyContext by its DbContext base type. From this point on Simple Injector will know that it will need to construct a MyContext in case someone asks for a DbContext . This is the whole purpose of

Program to an interface, not an implementation

In your case however, although you do register the MyContext by its abstraction, you request a new instance of MyContext directly, instead of requesting it through its abstraction. This causes Simple Injector to look for the MyContext in its list of registered abstractions. Since there is no registration for MyContext (there is for DbContext though, but that's a totally different type what Simple Injector is concerned), Simple Injector will try to add the missing registration. This succeeds because MyContext is concrete and has single resolvable constructor. By default, Simple Injector will resolve unregistered concrete types as Transient .

So MyContext is resolved as transient when requested directly. You can solve this by changing your test to the following:

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);
}

Do note that Simple Injector usually detects these kinds of mistakes. In case you register MyContext by its DbContext base type, but inject MyContext directly in a constructor of a type, Simple Injector will throw a Short Circuited Dependency error when calling Verify() .

The reason you didn't get warned about this, is because you've called Verify() before the resolve action (you should typically not call GetInstance from within your application; instead you should build all object graphs up front). But when you'd call Verify (again) after resolving MyContext you would see the exception popping up:

[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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM