Service owns disposable Repository that owns disposable DbContext - Dispose IDisposables injected with Unity

Service owns disposable Repository that owns disposable DbContext - Dispose IDisposables injected with Unity

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

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

我想一个更普遍的问题可能是,如果我有一个 class 引用了一个 class,它引用了另一个 class,... (等等)...,它引用了非托管或托管的一次性资源 - 他们应该 all 实现 IDisposable?

Unity DI 无法在对象的生命周期结束时处置对象,并且在 GC 决定收集它们之前您不能将它们留在那里。

理论上有DI框架实现了Register/Resolve/Release,Release就是调用dispose的地方,但是Unity没有实现Release部分。我不知道在 .NET 中是否有其他框架可以做到这一点。

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

1) 简单的技巧

不要注入DbContext,而是在你需要的地方从容器中解析,这样你就可以控制它的处置

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

警报!警报!服务定位器反模式

2) 智能解决方案

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

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

您的工厂可能看起来像这样:

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

以便可以通过构造函数注入来注入:

public MyService(IDbContextFactory dbContextFactory)
{
}

并且,如前所述,没有理由不将其注册为单例:您可以安全愉快地使用同一个工厂来构建大量 Db 上下文!

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

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

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

就 IDisposable 而言,我认为如果一个对象实现了 IDisposable,您需要对其进行 Dispose,即使有不调用 IDisposable 不会导致任何问题的示例。但这是一个实施细节,依赖它可能不安全(与 IDisposable 合同相反)。

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

如果它是 Web API 服务,您可以使用 Unity bootstrapper for ASP.NET Web API (along with the Unity bootstrapper for ASP.NET MVC. This will give a PerRequestLifetimeManager,它将为每个请求提供一个单例(不确定您是否需要这个,但这是常见的情况)。

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

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