【问题标题】:Dependency injection with Unit of Work pattern使用工作单元模式的依赖注入
【发布时间】:2021-11-10 10:17:42
【问题描述】:

我正在尝试在 C#/.NET 中为我的存储库实现工作单元模式。我的计划是将 UoW 作为存储库的参数。这是一个如何使用它的示例:

using (var uow = new UnitOfWork()) 
{
    var itemRepository = new ItemRepository(uow);
    itemRepository.Add(new Item());
    uow.Commit();
}

此外,对于简单的操作(不需要事务时),存储库应该能够在没有工作单元的情况下使用:

var itemRepository = new ItemRepository();
var item = itemRepository.Get(itemId);

UnitOfWork/Repository 可以从 ConnectionFactory 获取数据库连接。连接工厂通过依赖注入接收连接选项。但是,这是我的问题:存储库如何获取对 ConnectionFactory 实例的引用? 存储库是手动创建的,因此它们不能通过构造函数注入依赖项。一种选择是拥有存储库工厂,可以注入它们的依赖项。在这种情况下,用法可能是这样的:

using (var uow = new UnitOfWork()) 
{
    var itemRepository = itemRepositoryFactory.Create(uow);
    itemRepository.Add(new Item());
    uow.Commit();
}

该解决方案的缺点是每个存储库都需要自己的工厂,而且会有很多。 是否有其他解决方案可以规避此问题?

【问题讨论】:

  • 你为什么不通过 IoC 容器(在 web 应用程序的情况下)或 main 方法(在控制台类型的情况下)通过依赖注入创建 everything应用程序)?例如,不建议在您的应用程序启动阶段或Http request 开始之后之后实例化任何服务。
  • 唯一不通过 DI 实例化的组件是存储库。对于存储库,我必须能够提供 UoW 实例。一种选择是要求存储库方法使用 UoW 参数,但这使用起来有点麻烦。
  • 我没有使用实体框架,所以存储库是围绕原始 sql 查询的合理抽象。
  • @wekso 你在使用.Net Core吗?或者.Net Framework 带有依赖注入库(如Ninject)?如果您注册UnitOfWork(在请求范围中,以便在请求完成后处理它)并在某个构造函数中请求repository,会发生什么?

标签: c# .net dependency-injection repository unit-of-work


【解决方案1】:

我肯定会将 UOW 注册为作用域依赖项。

作用域依赖在创建它们的容器的生命周期内有效。通常,框架会从父容器生成一个子容器,以执行某些工作。例如,ASP.NET Core 为请求生成一个子容器,然后在请求完成时释放它。这意味着注入的 UOW 实例是整个对象图中的同一实例,仅针对该请求。

如果需要,您还可以创建自己的范围。例如,我已经这样做了两次:

  • 作业调度程序,让每个作业都在自己的范围内运行
  • 消息处理程序,以便在自己的范围内处理每条消息

这是使用 Microsoft 的 DI 框架实现此目的的方法:

var collection = new ServiceCollection();
collection.AddScoped<IUnitOfWork, UnitOfWork>();

var provider = collection.BuildServiceProvider();

var puow = provider.GetRequiredService<IUnitOfWork>();

for(int i = 0; i < 2; i++)
{
    //Create the new scope
    using var childContainer = provider.CreateScope();

    //IUnitOfWork will be a singleton instance in this scope. 
    var c1uow = childContainer.ServiceProvider.GetRequiredService<IUnitOfWork>();
    var c2uow =  childContainer.ServiceProvider.GetRequiredService<IUnitOfWork>();
    // This should true, since they come from the same scope.
    var sameScope = c1uow == c2uow;
    
    //With the requested IUnitOfWork from provider instead, it would be a different instance
    //Therefore, this should be false    
    var diffScope = puow == c1uow;
}

这将允许您简单地将 IUnitOfWork 注入每个 repo,而无需为每个 repo 创建工厂。

如果您在 ASP.NET Core 中编写应用程序,这将是开箱即用的。只需将依赖项注册为范围,就像这样

collection.AddScoped<IUnitOfWork, UnitOfWork>();

然后将其注入您需要的存储库中。您不必担心创建新范围,因为框架会为应用程序接收到的每个 http 请求为您创建。

我真的推荐阅读 Mark Seemann 的书“依赖注入原理、实践和模式”。它确实深入了解了依赖注入是什么以及它是如何工作的。不仅如此,我发现他还是一位伟大的作家。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 2020-01-03
    • 1970-01-01
    • 2018-02-11
    相关资源
    最近更新 更多