简体   繁体   English

使用InjectionConstructor时会弃用Unity WebApi DbContext,但如果没有,它会很好地工作

[英]Unity WebApi DbContext disposed when using InjectionConstructor, but works fine without it

Repositiory, OrderRequestRepository.cs 仓库,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 Unity.WebApi UnityConfig.cs

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

With the above line in UnityConfig.cs the first call to the api works, the second call fails with the error : 在UnityConfig.cs中的上述行中,对api的第一个调用有效,第二个调用失败,并显示以下错误:

The operation cannot be completed because the DbContext has been disposed. 由于已处置DbContext,因此无法完成该操作。

If I comment out the _context.Dispose() line, then it works, which is fine as Garbage Collection will clean up for me, but ideally I'd like to manage it myself. 如果我注释掉_context.Dispose()行,则它可以正常工作,因为Garbage Collection将为我进行清理,但理想情况下,我想自己进行管理。

Alternatively, if I use the below lines instead - without the InjectionConstructor - in the UnityConfig.cs then it also works fine. 另外,如果我在UnityConfig.cs中改用以下几行(不使用InjectionConstructor),那么它也可以正常工作。

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

But I want use the InjectionConstructor as I want to add another parameter to the OrderRequestRepository Constructor and manage the disposal. 但是我想使用InjectionConstructor,因为我想向OrderRequestRepository构造函数添加另一个参数管理处置。 Any suggestions as to why doing both causes the error? 关于为什么两者都会导致错误的任何建议?

Update 更新

I removed the IDisposable code, as suggested by Steven, and because 我删除了史蒂文(Steven)建议的IDisposable代码,原因是

  1. The general rule is that the one who creates an object should destroy it, so I'll leave my EF dbcontext (IntranetApplicationsContext) alone. 一般规则是,创建对象的对象应该销毁它,因此我将不理会我的EF dbcontext(IntranetApplicationsContext)。

  2. An IOC container (Unity.Webapi in my case) should handle disposal IOC容器(在我的情况下为Unity.Webapi)应处理

So with this line in UnityConfig 因此,在UnityConfig中使用这一行

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

Reads with EF are working, but interestingly when I try an edit I get the following error: 使用EF进行读取有效,但是有趣的是,当我尝试编辑时,出现以下错误:

Attaching an entity of type 'IntranetApplications.Infrastructure.Models.OrderRequest' failed because another entity of the same type already has the same primary key value. 附加类型为'IntranetApplications.Infrastructure.Models.OrderRequest'的实体失败,因为相同类型的另一个实体已经具有相同的主键值。 This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. 如果图形中的任何实体具有相互冲突的键值,则使用“附加”方法或将实体的状态设置为“不变”或“修改”时,可能会发生这种情况。 This may be because some entities are new and have not yet received database-generated key values. 这可能是因为某些实体是新实体,尚未收到数据库生成的键值。 In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate. 在这种情况下,请使用“添加”方法或“已添加”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

If I roll back and use the basic line in the UnityConfig 如果我回滚并在UnityConfig中使用基本行

container.RegisterType<IOrderRequestRepository, OrderRequestRepository>();

... everything works. ...一切正常。 I believe both lines are using the the same default lifetime manager, TransientLifetimeManager, so it's odd that using InjectionConstructor still seems to break things. 我相信这两行都使用相同的默认生命周期管理器TransientLifetimeManager,因此使用InjectionConstructor似乎仍然会破坏事情很奇怪。

The problem here is that your OrderRequestRepository is disposing stuff it doesn't own. 这里的问题是您的OrderRequestRepository正在处理它不拥有的东西。 The IntranetApplicationsContext is injected into the repository and since the OrderRequestRepository has no idea what the lifestyle of that dependency is, it cannot dispose it. IntranetApplicationsContext已注入到存储库中,并且由于OrderRequestRepository不知道该依赖项的生活方式是什么,因此无法处理它。

You probably registered the IntranetApplicationsContext to have a per-request lifestylem while your repository is transient. 您可能注册了IntranetApplicationsContext以在存储库处于暂态状态时具有按请求的生活方式。

Solution: only implement IDisposable if you have anything to dispose itself. 解决方案:仅当您有需要处理的东西时才实现IDisposable。 In your case that means that your repository doesn't need to IDisposable at all. 在您的情况下,这意味着您的存储库根本不需要IDisposable。

I've got around this, rather than fix the error: 我已经解决了这个问题,而不是解决错误:

I was using InjectionConstructor so I could pass multiple parameters, but as an alternative I have changed it so that I pass a single parameter, a Factory object to the repository instead. 我正在使用InjectionConstructor,以便可以传递多个参数,但是作为替代方案,我对其进行了更改,以便我将单个参数(工厂对象)传递给存储库。

public class OrderRequestRepository : IOrderRequestRepository
{
    private readonly IntranetApplicationsContext _context;
    private readonly ILogger _logger;

    public OrderRequestRepository(IOrderRequestRepositoryFactory respositoryFactory)
    {
        _context = respositoryFactory.CreateIntranetApplicationsContext();
        _logger = respositoryFactory.CreateLogger();
    }

    ...
}

Factory

public interface IOrderRequestRepositoryFactory
{
    ILogger CreateLogger();
    IntranetApplicationsContext CreateIntranetApplicationsContext();
}

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

    public IntranetApplicationsContext CreateIntranetApplicationsContext()
    {
        return new IntranetApplicationsContext();
    }
}

UnityConfig UnityConfig

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

This works in that, I am not using the InjectionConstructor, so don't get the associated errors and can still pass as many parameters as I want, by using my Factory. 这样做的原因是,我没有使用InjectionConstructor,所以没有得到相关的错误,并且仍然可以通过使用Factory传递尽可能多的参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM