在ASP.NET Core依赖注入中重写生命周期

7

我已经使用标准代码注册了一个Entity Framework DBContext,像这样:

public void ConfigureServices(IServiceCollection services)
{
    [...]
    services.AddDbContext<MyDbContextType>(ServiceLifetime.Scoped);
}

这对需要 EF 服务的控制器调用的服务非常有效。

然而,我有一些特殊的控制器。它们在新线程上启动作业,在 web 请求的生命周期之外运行。当这些作业使用我的 DbContext(或使用使用我的 DbContext 的服务)时,会抛出错误,因为已经释放了范围实例。

是否有一种方法可以覆盖注入的 DbContext 的服务生命周期,只针对某些控制器?或者您能推荐其他解决方案吗?

1个回答

10

你不应该覆盖这个行为。相反,你在后台线程上运行的代码应该在自己的作用域中运行。这意味着后台线程第一件要做的事情就是使用IServiceScopeFactory创建一个新的IServiceScope。从这个作用域中解析你想要使用的服务并调用该服务。在操作结束时,释放你的作用域。

例如:

private IServiceScopeFactory factory;

new Thread(() => 
{
    using (var scope = this.factory.CreateScope())
    {
        // Resolve
        var service = scope.ServiceProvider.GetRequiredService<IService>();

        // Use
        service.DoStuff();

        // Dispose scope
    }
}).Start();

了解如何在多线程应用程序中使用 DI,请查看此文档。尽管该文档是针对特定 DI 容器编写的,但它具有通用性,其中的建议同样适用于您的 DI 容器。


这听起来很不错,我会试一试。谢谢! - James Orr
1
这个章节:https://simpleinjector.readthedocs.io/en/latest/howto.html#work-with-dependency-injection-in-multi-threaded-applications 展示了一个SimpleInjector的示例,其中注入了一个Func<IFoo>以获取一个IFoo工厂。通过这样做,“我们防止应用程序代码依赖于容器本身(这应该被防止)。”您是否知道ASP.NET DI中是否有类似的功能?只是好奇,我正在尝试您的代码示例。 - James Orr
@JamesOrr:在ASP.NET DI中没有这样的功能。这是一种非常幼稚的实现,有很多限制。 - Steven
我可以了解一下您如何获取对 IServiceScopeFactory 的引用吗? - vmachacek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接