服务拥有一次性存储库,拥有一次性DbContext - 配置使用Unity注入的IDisposables

时间:2015-05-06 15:44:25

标签: c# entity-framework architecture dependency-injection idisposable

我有一个服务,一个存储库和一个DbContext。存储库拥有DbContext,服务拥有存储库。

我的存储库应该实现IDisposable吗?如果是这样,我的服务是否也应该实现IDisposable并处置存储库?

我想一个更普遍的问题可能是,如果我有一个类有一个类的引用,它有一个对另一个类的引用,...(等等)...,它有一个引用非托管或托管的可支配资源 - 他们所有实施IDisposable吗?

2 个答案:

答案 0 :(得分:3)

Unity DI没有办法在生命周期结束时处理对象,并且在GC决定收集它们之前你不能将它们留在那里。

理论上有DI框架实现了Register / Resolve / Release,而Release将是调用dispose的地方,但Unity并没有实现Release部分。我不知道是否还有其他框架可以在.NET中执行此操作。

使用Unity,有两种解决方案:

1)轻松破解

不要注入DbContext,但要在您需要的地方从容器中解析它,以便您可以控制它的处置

using(var ctx = container.Resolve<MyDbContext>())
{
}

<强> ALARM!报警!服务定位器反模式

2)智能解决方案

在您需要时注入可以为您提供DbContext的工厂。如果你这样做,而不是注入一个DbContext,你可以注入一个类,它可以在你需要时为你提供DbContext:一个工厂。您可以将工厂注册为DI容器中的单件,因为您将连续使用它

using(var ctx = DbContextFactory.GetContex())
{
}

你的工厂看起来像这样:

public class DbContextFactory : IDbContextFactory
{
   public DbContext GetDbContext()
   {
      ...
   }
}

因此可以通过构造函数注入注入:

public MyService(IDbContextFactory dbContextFactory)
{
}

并且,正如所解释的那样,没有理由不将其注册为单身人士:您可以安全而愉快地使用相同的工厂来构建大量的Db上下文!

注意:如果你使用一个抽象工厂会好得多,而不是返回具体对象返回一个接口实现,这是一个小小的改变

public class DbContextFactory : IDbContextFactory
{
   public IDbContext GetDbContext()
   {
      ...
   }
}

您可以阅读此内容以获取更多信息和样本:

答案 1 :(得分:2)

就IDisposable而言,我认为如果一个对象实现了IDisposable,你需要处理它,即使有些例子没有调用IDisposable也不会导致任何问题。但这是一个实施细节,依赖它可能不安全(与IDisposable合同相反)。

您没有提及您正在使用的服务类型,但您确实提到您使用的是Unity。

如果是Web API服务,您可以使用Unity bootstrapper for ASP.NET Web API(以及Unity bootstrapper for ASP.NET MVC。这会产生一个PerRequestLifetimeManager,每个请求会给出一个单例(不确定)如果您需要或不需要,但这是常见的情况。)

此外,还安装了IHttpModule,UnityPerRequestHttpModule,它将在HTTP请求结束时(使用PerRequestLifetimeManager注册)处理IDisposable对象实例。

如果使用其他服务堆栈(例如WCF),那么您可以自己实施类似的东西,或者使用JotaBe答案中概述的工厂方法。