【问题标题】:Entity Framework DbContext is NOT disposed using dependency injection实体框架 DbContext 不使用依赖注入进行处置
【发布时间】:2020-07-05 08:51:40
【问题描述】:

我在解决方案中有以下设置:

编辑:可以找到演示解决方案 here

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

实体框架核心:

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

使用 Microsoft.Extensions.DependencyInjection 将所有内容链接在一起的“CompositionRoot”:

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 能够被处理。 有人知道为什么会发生这种情况以及如何解决吗?

编辑:一些额外的日志

  • 2020-03-24 21:09:29.5727|在 DataContext 中注入的选项
  • 2020-03-24 21:09:29.6064|在 DataContext 中注入身份验证
  • 2020-03-24 21:09:29.6064|在 DataContext 中注入的记录器
  • 2020-03-24 21:09:29.6262|创建的 DataContext 1ddd98a1-a8f9-4096-8a11-c0b4d40d01ae
  • 2020-03-24 21:09:30.1918|在 CustomerService 中注入记录器
  • 2020-03-24 21:09:30.2200|在 CustomerService 中注入的 DataContext
  • 2020-03-24 21:09:30.2300|在 CustomerService 中注入映射器
  • 2020-03-24 21:09:30.2482|在 CustomerService 中注入身份验证
  • 2020-03-24 21:09:30.2482|创建 CustomerService 5b446267-d908-4291-9918-af1841324708
  • 2020-03-24 21:09:30.2769|在 CustomerController 中注入的记录器
  • 2020-03-24 21:09:30.2769|CustomerService 在 CustomerController 中注入
  • 2020-03-24 21:09:30.3186|CustomerController.GetCustomer(4)
  • 2020-03-24 21:09:35.0599|处理 CustomerService 5b446267-d908-4291-9918-af1841324708

编辑 3 月 25 日: 我尝试使用没有接口的 DataContext,但问题仍然存在。我真的不知道我做错了什么!

【问题讨论】:

  • DI 很像“托管代码”用于内存 - DI 容器可以决定何时(或是否)“处置”对象。另外:简单地使一个注入对象(例如服务)依赖于另一个(例如 DBContext)可能会影响后者。见Captive Dependencies
  • 我明白,我什至将 serviceLifeTime 添加到 DataContext 但没有成功。据我所知,所有其他服务都是瞬态的。
  • 我知道这是一篇旧帖子,但仅供参考。对我来说,我重写了 Dispose 方法,而我应该重写 DisposeAsync 方法。

标签: c# dependency-injection entity-framework-core asp.net-core-webapi


【解决方案1】:

您没有正确注册 DbContext

使用AddDbContext的以下重载

services.AddDbContext<IDataContext, DataContext>(options =>  
    options.UseSqlServer(configuration.GetConnectionString("myConnection")));

这会将接口/抽象与具体实现相关联。

并删除临时注册

services.AddTransient<IDataContext, DataContext>();

【讨论】:

  • 这可行,但不能解决问题。我已删除 services.AddTransient();一切都像以前一样工作。我在我的问题中添加了一些日志。
【解决方案2】:

也面临这个问题(实际上是问题吗?)。我有 ASP.Net Core WebApi 项目(框架 = net 5.0)并使用 AddDbContext 将其注入 MVC 控制器。根据文章,它应该将 db-context 添加为“Scoped”。根据我的期望,在这种情况下,db-context 应该根据每个 http 请求(就是这样)进行实例化,并在 MVC-Controller 生命周期的范围内隐式处理 - 但由于某种原因它不会发生.. 可能会导致在“The instance of entity type {} cannot be tracked because another instance with the key value {} is already being tracked.”中(这是我来这里的原因)

我相信,它可以通过在代码中添加“使用”结构或从控制器调用 Dispose() 来解决

protected override void Dispose(bool disposing = true)
        {
            Console.WriteLine("Controller dispose.");
            _dbContext.Dispose(); //your db-context (injected in controller)
            base.Dispose(disposing);
        }

但不确定这是正确的解决方案..

【讨论】:

    猜你喜欢
    • 2016-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多