Unity WebApi DbContext在使用InjectionConstructor时处理,但没有它就能正常工作

时间:2014-09-30 17:35:04

标签: c# asp.net-web-api unity-container dispose dbcontext

Repositiory,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构造函数中添加另一个参数,并且管理处理。有关为什么两者都会导致错误的任何建议?

更新

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

  1. 一般规则是创建对象的人应该销毁它,因此我将单独留下我的EF dbcontext(IntranetApplicationsContext)。

  2. IOC容器(在我的情况下是Unity.Webapi)应该处理

  3. 所以使用UnityConfig中的这一行

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

    使用EF读取功能正在发挥作用,但有趣的是,当我尝试编辑时,我收到以下错误:

      

    附加类型的实体   &#39; IntranetApplications.Infrastructure.Models.OrderRequest&#39;失败   因为同一类型的另一个实体已经具有相同的主要实体   核心价值。使用&#39;附加&#39;方法或设置   一个实体的状态为“未变”&#39;或者&#39;修改&#39;如果有任何实体   图表具有冲突的键值。这可能是因为一些   实体是新的,尚未收到数据库生成的密钥   值。在这种情况下,请使用&#39;添加&#39;方法或“添加”#39;实体国家   跟踪图形,然后将非新实体的状态设置为   &#39;不变&#39;或者&#39;修改&#39;酌情。

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

    container.RegisterType<IOrderRequestRepository, OrderRequestRepository>();
    

    ......一切正常。我相信这两行都使用相同的默认生命周期管理器TransientLifetimeManager,所以使用InjectionConstructor似乎仍然会破坏事情,这很奇怪。

2 个答案:

答案 0 :(得分:1)

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

您的存储库是暂时的,您可能已注册IntranetApplicationsContext以获得按请求生活方式。

解决方案:如果您有任何可自行处理的内容,则只能实现IDisposable。在您的情况下,这意味着您的存储库根本不需要IDisposable。

答案 1 :(得分:1)

我已经解决了这个问题,而不是修复错误:

我正在使用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,所以不要通过使用我的工厂来获取相关的错误,并且仍然可以传递任意数量的参数。