【问题标题】:Dependency Injection lifetimes for a Factory工厂的依赖注入生命周期
【发布时间】:2021-02-07 13:28:19
【问题描述】:

我有一个 .Net Core 3.1 Web API,我有以下依赖项:

  1. 作为 Scoped SomeDbContext(使用 AddDbContextPool)。
  2. 作为Transient SomeDbRepository,接收上述SomeDbContext
  3. 作为Transient SomeService,接收上述SomeDbRepository
  4. 作为SomeServiceSingleton工厂。

这里是在 Startup.cs 中注入依赖的代码

services.AddDbContextPool<SomeDbContext>(options => options.UseSqlServer("connectionsString"));

services.AddTransient<SomeDbRepository>();// recive SomeDbContext
services.AddTransient<SomeService>();// recive SomeDbRepository

//Factory for SomeService
services.AddSingleton<Func<SomeService>>(provider => () =>
{
    return provider.GetService<SomeService>();
});    

API 控制器

//API Controller
public SomeController(Func<SomeService> factory)
{
    _someService = factory.Invoke();
} 

当我在多线程环境中调用我的 API 时出现错误:

错误:在前一个操作之前在此上下文上启动了第二个操作 完全的。这通常是由于不同的线程使用相同的 DbContext 实例

为什么我的 DbContext 被不同的线程使用?它假设工厂为每个请求返回一个新的作用域 DbContext。我只使用(调用)工厂一次 por 请求。

如果我将工厂的生命周期从 Sinlgeton 更改为 Scoped,它可以正常工作。但我不知道为什么?为什么会影响工厂的生命周期?有人可以解释一下为什么它会这样工作。非常感谢大家!!

【问题讨论】:

  • 调试代码时是否看到调用了工厂?
  • @Alexei Levenkov 是的,每次请求都会调用工厂。当我调试时,我会根据每个请求进入工厂。

标签: c# multithreading asp.net-core .net-core dependency-injection


【解决方案1】:

Singleton 注册委托的IServiceProvider 参数提供对 范围的引用。 Scoped(和IDisposable Transient)服务在它们解析的范围内进行跟踪,并且由于根提供程序有自己的范围,从根IServiceProvider解析会导致Scoped(和IDisposable Transient)服务被缓存以供该根提供者的生命周期。这通常意味着:只要应用程序运行,它们就会一直存在。

这意味着,在 MS.DI 容器的上下文中,将委托注册为从 IServiceProvider 参数解析的 Singleton 通常是一个坏主意,因为它会导致已解析的 Scoped 依赖项意外成为 Singleton (他们成为意外Captive Dependencies)。使用IDisposable Transients,它变得更加隐含,因为从根提供程序解析它们甚至可能导致内存泄漏,因为它们只会在应用程序关闭时被释放。

虽然在代理只解析其他单例(或非一次性瞬态)时将其注册为单例是可以的,但这通常是非常脆弱的,因为将来很容易更改它,以一种不小心造成麻烦的方式.

相反,使用 MS.DI,最好将您的工厂代表注册为 Scoped:

services.AddScoped<Func<SomeService>>(provider => () =>
{
    return provider.GetService<SomeService>();
}); 

请注意,此建议特定于 MS.DI,可能不适用于其他 DI 容器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多