如何使用简单注入器在嵌套方法中获取 DbContext

How to get DbContext in nested methods using Simple Injector

我有疑问,因为我是依赖注入和 IoC 的新手。

我有一个域层(带有业务逻辑)和一个数据层。我们不实现存储库,我们直接使用 EF Core。 它是一个 Class 库项目,我们在 ASP.NET CCore Web API、WinForms 和另一个框架中使用它。

想法是在一个范围内使用相同的上下文。

问题是我无法在嵌套方法执行中获得相同的上下文,我确定这是因为我没有完全理解这个概念,你们能帮我吗?

示例:

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

在 Simple Injector 中,您通过抽象来注册一个实现。在您的情况下,您通过 DbContext 基本类型注册了 MyContext。从这一点开始,Simple Injector 将知道它需要构造一个 MyContext 以防有人请求 DbContext。这就是

的全部目的

Program to an interface, not an implementation

但是,在您的情况下,尽管您确实通过抽象注册了 MyContext,但您直接请求了 MyContext 的新实例,而不是通过其抽象来请求它。这会导致 Simple Injector 在其已注册抽象列表中查找 MyContext。由于没有 MyContext 的注册(虽然有 DbContext 的注册,但与 Simple Injector 所关注的类型完全不同),Simple Injector 将尝试添加丢失的注册。这是成功的,因为 MyContext 是具体的并且具有单个可解析构造函数,而您使用的是简单注入器 v4.x.

默认情况下,旧版本的 Simple Injector 会将未注册的具体类型解析为 Transient。此默认值在 v5 中更改,默认情况下它不会创建任何未注册的具体类型。

因此 MyContext 在直接请求时被解析为瞬态。您可以通过将测试更改为以下内容来解决此问题:

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

请注意,Simple Injector 通常会检测到这些类型的错误。如果您通过其 DbContext 基类型注册 MyContext,但直接在类型的构造函数中注入 MyContext,Simple Injector 在调用 [=27 时将抛出 Short-Circuited Dependency 错误=].

您没有收到警告的原因是您在解决操作之前调用了 Verify()(您通常不应从应用程序中调用 GetInstance;相反,您应该预先构建所有对象图)。但是当你在解析 MyContext 之后(再次)调用 Verify 时,你会看到异常弹出:

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