【问题标题】:Injecting UnitOfWork in a Using block在 Using 块中注入 UnitOfWork
【发布时间】:2012-10-31 15:01:13
【问题描述】:

我在 UnitOfWork / Repository / MVC 应用程序上工作。现在这一切都很好,我想将 UnitOfWork 与控制器分离。一种方法是在控制器的构造函数中使用 Ninject (或其他)注入依赖项。但是,这意味着 UnitOfWork 将与控制器同时实例化。

我想使用我的 UnitOfWork 的方式是使用这样的块:

using(var unitOfWork = new IUnitOfWork)
{
    return unitOfWork.GetRepository<IEmployeesRepository>().GetAllEmployees();
}

显然你不能实例化一个接口,你有一个用依赖注入器注入的实现实例,但是我如何在 using 子句中注入它?

我看到了属性注入和方法注入,但我不确定如何使用它们来实现我的目标。

【问题讨论】:

    标签: asp.net-mvc design-patterns ninject repository-pattern unit-of-work


    【解决方案1】:

    使用您在容器中注册的工厂:

    public class UserController : Controller
    {
        IUnitOfWorkFactory _factory;
    
        public UserController(IUnitOfWorkFactory factory)
        {
            _factory = factory;
        }
    
        public ActionResult DoSomething()
        {
            using(var unitOfWork = _factory.Create())
            {
                return unitOfWork.GetRepository<IEmployeesRepository>().GetAllEmployees();
            }
        }
    }
    

    恕我直言,最好抽象出 UoW 处理:http://blog.gauffin.org/2012/06/how-to-handle-transactions-in-asp-net-mvc3/

    【讨论】:

    • +1 这是一个好方法。 @Pluc 如果您真的打算在 Ninject 中使用这种方法,请务必查看 Ninject.Extensions.Factory,它会自动生成与上述等效的方法
    • 你是对的,抽象 UoW 处理感觉少了很多反模式。谢谢。 @RubenBartelink 感谢您提供扩展信息,但我觉得这是不合理的,因为手动编写我的工厂大约需要 5 行代码。
    • @Pluc 与往常一样,这取决于您有多少案例以及许多其他问题
    • 是的,当然。就我而言,我认为不值得额外的插件。这就是为什么我感谢你但没有使用它的原因。 :) 地狱,我什至会投票赞成你的评论! :)
    【解决方案2】:

    您可以通过 Autofac 轻松做到这一点。我确信其他 IoC 容器应该具有相同的功能。

    这里是wiki的链接。

    代码示例:

    public class UserController : Controller
    {
        Func<Owned<IUnitOfWork>> unitOfWorkFactory;
    
        public UserController(Func<Owned<IUnitOfWork>> unitOfWorkFactory)
        {
            this.unitOfWorkFactory = unitOfWorkFactory;
        }
    
        public ActionResult DoSomething()
        {
            using(var unitOfWork = this.unitOfWorkFactory().Value)
            {
                return unitOfWork.GetRepository<IEmployeesRepository>().GetAllEmployees();
            }
        }
    }
    

    无需额外注册,只需注册您的接口实现即可。

    【讨论】:

      【解决方案3】:

      您不必在 using 块中实例化变量,您可以使用现有变量。所以,你可以像这样使用方法注入:

      public ActionResult Index(IUnitOfWork unit)
      {
          using(unit)
          {
               // Do some work....
          }
      
          // Return an action
      }
      

      只是理解单元会在离开 using 块后被丢弃,所以它不应该被使用。

      【讨论】:

      • 我不太喜欢开始在任何地方添加 UnitOfWork 作为方法参数的想法......我希望尽可能保持依赖注入离散
      【解决方案4】:

      [..] 如何在 using 子句中注入它?

      将不再有using 子句。如果 IoC 容器注入依赖项,它负责它的生命周期。

      释放依赖项不是一个好习惯(using 正是这样做的)。


      我看到了属性注入和方法注入

      尽可能使用构造函数注入。属性/方法注入在一些特殊情况下有其用途。

      构造函数注入的好处是类可以立即清楚地说明它的依赖关系。此外,您只能在提供所有需要的依赖项后创建实例。

      使用属性注入,您可能会忘记设置所需的依赖项。仅在依赖项是可选的、具有默认实现或破坏循环依赖图的情况下才使用此选项。

      使用方法注入,您可能会一次又一次地使用相同的方法参数使代码膨胀。


      [...] 如果我想在该控制器的同一个实例中使用 UnitOfWork 两次会发生什么。 Ninject 会再次注入吗?

      Ninject 将注入同一个实例两次,或者创建两个不同的实例,具体取决于您指示它的行为方式。

      IoC 容器允许您为注入的组件指定/配置生命周期样式。对于 Ninject,请参阅 how to specify Object Scopes

      【讨论】:

      • 我认为使用 dbContext 的最佳实践是在您需要它之前进行实例化,并在之后立即处理它。这就是为什么我将我的 UnitOfWork 设为一次性的,以便它(在某种程度上)可以作为上下文的包装器。当您实例化它时,会创建 dbContext,然后当您处置它时,它会提交并处置 dbContext。那么 UnitOfWork 是否应该管理 DbContext 的生命周期?仅在请求时创建 dbContext,并在提交后处置?或者我应该让它随它去,dbContext 将在控制器被处置时得到处理?
      • 另外,在我的 BaseController 中添加它(我所有的控制器都扩展)而不是使用构造函数是不好的做法吗? [Inject] protected IUnitOfWork unitOfWork { get; set; } 我仍然可以通过像 new EmployeeController { unitOfWork = new MockUnitOfWork(); } 这样创建我的控制器来进行模拟,这样我就不用在每个控制器中编写构造函数了。
      • @Pluc 可以让UnitOfWork 提交DbContext;只要确保发生这种情况。
      • @Pluc 控制它的基本控制器的想法不错。我也看到过这个在使用here(虽然这个用的是RavenDB而不是SQL,但是原理是一样的)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-14
      相关资源
      最近更新 更多