【问题标题】:How to get DbContext in nested methods using Simple Injector如何使用 Simple Injector 在嵌套方法中获取 DbContext
【发布时间】:2021-10-28 04:43:29
【问题描述】:

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

我有一个领域层(带有业务逻辑)和一个数据层。我们不实现存储库,我们直接使用 EF Core。 它是一个类库项目,我们在 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;
    }
}

【问题讨论】:

    标签: c# dbcontext simple-injector


    【解决方案1】:

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

    编程到接口,而不是实现

    但是,在您的情况下,尽管您确实通过其抽象注册了 MyContext,但您直接请求 MyContext 的新实例,而不是通过其抽象请求它。这会导致 Simple Injector 在其注册抽象列表中查找MyContext。由于MyContext 没有注册(虽然DbContext 有注册,但Simple Injector 关注的是完全不同的类型),Simple Injector 将尝试添加缺少的注册。这成功了,因为MyContext 是具体的并且具有单个可解析的构造函数,而您使用的是 Simple Injector 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 将在调用Short-Circuited Dependency 时抛出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();
    }
    

    【讨论】:

    • 感谢您分享您的知识。
    • 感谢您分享您的知识。我还有很多东西要学,你认为这对我来说是最好的选择吗?我对表示层的访问权限有限,我们在业务层和数据层下工作,并且在执行一些业务规则时需要共享相同的上下文。所有项目都是类库。我怎么能不从我的业务逻辑中调用 GetInstance 并事先构建图表?
    • @Lucus:你不会打电话给GetInstance。您在应用程序的启动路径(组合根)中注册所有对象。并且所有实例都是使用构造函数注入接收的。您构建深度对象图。
    猜你喜欢
    • 1970-01-01
    • 2018-04-18
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多