Entity Framework DbContext在使用依赖注入时没有被释放

3

我有一个解决方案的设置如下:

编辑:演示解决方案可以在此处找到这里

ASP.NET Core Web API:

public class MyController : ControllerBase
{
    private readonly IMyService _service;
    public MyController(IMyService service)
        {
             _service = service;
        }
}

服务层:

public class MyService: IMyService, IDisposable
{
    private readonly IDataContext _context;
    public MyService(IDataContext context)
        {
             _context = context;
        }
}

Entity Framework Core:

public class DataContext : DbContext, IDataContext, IDisposable
{
    public DataContext(DbContextOptions<DataContext> options, IAuthenticationService authentication, ILogger<DataContext> logger) : base(options) 
        {
            ...
        }
}

使用 Microsoft.Extensions.DependencyInjection 的“组合根”将所有内容链接起来:
services.AddDbContext<DataContext>(options =>  options.UseSqlServer(configuration.GetConnectionString("myConnection")), ServiceLifetime.Transient);
services.AddTransient<IMyService, MyService>();
//EDIT: removed this line
//services.AddTransient<IDataContext, DataContext>(); 

这些代码按预期工作,但我的DataContext从未被销毁。我已在Dispose方法中添加日志以监视此行为,但我无法弄清楚为什么会发生这种情况(或为什么在这种情况下不会发生)。 我尝试了重新排序“AddTransient”但没有成功(正如预期的那样),以及使用“AddScoped”而不是“AddTransient”。我在单元测试中使用接口来模拟DbContext,但我也希望我的DbContext能够被销毁。 有人知道为什么会出现这种情况以及如何解决吗? 编辑:一些额外的日志 Options注入到DataContext中 身份验证注入到DataContext中 记录器注入到DataContext中 创建DataContext 1ddd98a1-a8f9-4096-8a11-c0b4d40d01ae 记录器注入到CustomerService中 将DataContext注入到CustomerService中 将Mapper注入到CustomerService中 身份验证注入到CustomerService中 创建CustomerService 5b446267-d908-4291-9918-af1841324708 记录器注入到CustomerController中 将CustomerService注入到CustomerController中 CustomerController.GetCustomer(4) 处置CustomerService 5b446267-d908-4291-9918-af1841324708 编辑3月25日: 我尝试了使用没有接口的DataContext,但问题仍然存在。我真的不知道我做错了什么!

2
DI 很像内存中的“托管代码” - DI 容器可以决定何时(或是否)“处理”对象。此外:仅仅使一个注入的对象(例如服务)依赖于另一个对象(例如 DBContext)可能会影响后者。请参见俘获依赖项 - FoggyDay
我理解了,我甚至将serviceLifeTime添加到了DataContext中,但没有成功。据我所知,所有其他服务都是短暂的。 - Berrepoot
我知道这是一个旧帖子,但对于参考。对我来说,我正在覆盖Dispose方法,而我应该覆盖DisposeAsync方法。 - user1515791
2个回答

2
您没有正确注册DbContext。
请使用以下的AddDbContext重载方法。
services.AddDbContext<IDataContext, DataContext>(options =>  
    options.UseSqlServer(configuration.GetConnectionString("myConnection")));

这将把接口/抽象与具体实现关联起来。

并删除临时注册。

services.AddTransient<IDataContext, DataContext>();

这个方法可以运行,但并没有解决问题。我已经移除了 services.AddTransient<IDataContext, DataContext>(); ,现在一切都像以前一样工作了。我在我的问题中添加了一些日志。 - Berrepoot

1
面临着这个问题(实际上是问题吗?)。我有一个ASP.Net Core WebApi项目(框架=net 5.0),并使用AddDbContext将其注入到MVC-Controller中。根据文章,它应该将db-context添加为“Scoped”。按照我的期望,在这种情况下,db-context应该在每个http请求中被实例化(就是这样),并在MVC-Controller生命周期范围内隐式地被处理,但由于某些原因没有发生...潜在地,它可能会导致“实体类型{}的实例无法跟踪,因为已经正在跟踪具有键值{}的另一个实例。”(这就是我来这里的原因)。
我相信,可以通过在代码中添加“using”构造或从控制器中调用Dispose()来解决这个问题。
protected override void Dispose(bool disposing = true)
        {
            Console.WriteLine("Controller dispose.");
            _dbContext.Dispose(); //your db-context (injected in controller)
            base.Dispose(disposing);
        }

但不确定它是否是正确的解决方案。

似乎没有人遇到过这个问题。 - Sergey Skrynnik
请问您将此添加在哪里?我在一个使用 Microsoft 依赖注入的 WinForms 项目中遇到了类似的问题 - 尽管在我的情况下,我认为还没有人在 WinForms 中使用 DI! - Richard Griffiths
我在我的Controller类中添加了这个,因为在Asp.net core中它是IDsiposable。但最终,我发现这种方法是不正确的,并通过另一种方式解决了这个问题。在你的情况下,由于你处理winforms(并使用DI with threm...OMG),我建议你 - Sergey Skrynnik
尝试使用IServiceScopeFactory.CreateScope方法。您可以控制何时应该处理DI服务的释放。 - Sergey Skrynnik

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