Unity WebApi DbContext在使用InjectionConstructor时被释放,但没有它也能正常工作

本文关键字:常工作 工作 DbContext WebApi InjectionConstructor 释放 Unity | 更新日期: 2023-09-27 18:25:16

存储库,OrderRequestRepository.cs

 public OrderRequestRepository(IntranetApplicationsContext context, ILogger logger)
    {
        _context = context;
        _logger = logger;
    }

...CRUD Methods
 public void Dispose()
    {
        Dispose(true);
    }
 protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
           _context.Dispose();
        }
        GC.SuppressFinalize(this);
    }

Unity.WebApi UnityConfig.cs

 container.RegisterType<IOrderRequestRepository, OrderRequestRepository>(new InjectionConstructor(new IntranetApplicationsContext() , new ElmahLogger()));

对于UnityConfig.cs中的上述行,对api的第一次调用有效,第二次调用失败,错误为:

操作无法完成,因为DbContext已被释放

如果我注释掉_context.Dispose()行,那么它就工作了,这很好,因为垃圾回收会为我清理,但理想情况下我想自己管理它。

或者,如果我在UnityConfig.cs中使用以下行,而不使用InjectionConstructor,那么它也可以正常工作。

container.RegisterType<ILogger, ElmahLogger>();
container.RegisterType<IOrderRequestRepository, OrderRequestRepository>();

但我想使用InjectionConstructor,因为我想向OrderRequestRepository Constructor添加另一个参数管理处置。关于为什么两者都会导致错误,有什么建议吗?

更新

按照史蒂文的建议,我删除了IDisposable代码,因为

  1. 一般规则是,创建对象的人应该销毁它,所以我将不使用我的EF dbcontext(IntranetApplicationsContext)。

  2. IOC容器(在我的例子中是Unity.Webapi)应该处理处理

因此,在UnityConfig 中使用这一行

container.RegisterType<IOrderRequestRepository, OrderRequestRepository> (new InjectionConstructor(new IntranetApplicationsContext(), new ElmahLogger()));

EF读取是有效的,但有趣的是,当我尝试编辑时,我会得到以下错误:

附加类型为的实体"IntranetApplications.Infrastructure.Models.OrderRequest"失败因为同一类型的另一个实体已经具有相同的主实体键值。使用"Attach"方法或设置时可能会发生这种情况如果中的任何实体该图具有冲突的键值。这可能是因为实体是新的,尚未收到数据库生成的密钥价值观在这种情况下,请使用"Add"方法或"Added"实体状态以跟踪图形,然后将非新实体的状态设置为"未更改"或"已修改"(视情况而定)。

如果我回滚并使用UnityConfig 中的基本行

container.RegisterType<IOrderRequestRepository, OrderRequestRepository>();

一切正常。我相信这两行都使用了相同的默认生存期管理器TransientLifetimeManager,所以奇怪的是,使用InjectionConstructor似乎仍然会破坏一些东西。

Unity WebApi DbContext在使用InjectionConstructor时被释放,但没有它也能正常工作

这里的问题是OrderRequestRepository正在处理它不拥有的东西。IntranetApplicationsContext被注入到存储库中,由于OrderRequestRepository不知道该依赖项的生活方式,因此无法处理它

您可能注册了IntranetApplicationsContext,以便在存储库处于临时状态时具有按请求的生活方式。

解决方案:只有当您有任何东西要自行处理时,才实现IDisposable。在您的情况下,这意味着您的存储库根本不需要IDisposable。

我绕过了这个问题,而不是修复错误:

我使用的是InjectionConstructor,这样我就可以传递多个参数,但作为替代方案,我对其进行了更改,以便将一个参数,一个Factory对象传递到存储库。

public class OrderRequestRepository : IOrderRequestRepository
{
    private readonly IntranetApplicationsContext _context;
    private readonly ILogger _logger;
    public OrderRequestRepository(IOrderRequestRepositoryFactory respositoryFactory)
    {
        _context = respositoryFactory.CreateIntranetApplicationsContext();
        _logger = respositoryFactory.CreateLogger();
    }
    ...
}

工厂

public interface IOrderRequestRepositoryFactory
{
    ILogger CreateLogger();
    IntranetApplicationsContext CreateIntranetApplicationsContext();
}
public class OrderRequestRepositoryFactory : IOrderRequestRepositoryFactory
{
    public ILogger CreateLogger()
    {
        return new ElmahLogger();
    }
    public IntranetApplicationsContext CreateIntranetApplicationsContext()
    {
        return new IntranetApplicationsContext();
    }
}

UnityConfig

container.RegisterType<ILogger, ElmahLogger>();
container.RegisterType<IOrderRequestRepository, OrderRequestRepository>();
container.RegisterType<IOrderRequestRepositoryFactory, OrderRequestRepositoryFactory>();

这样做的原因是,我没有使用InjectionConstructor,所以不会得到相关的错误,并且仍然可以通过使用我的Factory传递我想要的任意多的参数。