C# 在ASP.NET MVC 3中的多个服务之间共享工作单元

C# 在ASP.NET MVC 3中的多个服务之间共享工作单元,c#,asp.net-mvc,architecture,C#,Asp.net Mvc,Architecture,我的控制器使用2个或更多服务。反过来,我的服务构造并使用它们自己的工作类单元实例(具有对存储库的访问权) 我希望我的服务共享同一个工作单元实例,并使其可进行单元测试。我的问题是: 我是否应该将工作单元和服务注入控制器 我还需要将工作单元注入到我的服务中。哪里 我应该那样做吗?非常感谢你 1) 我不认为在UI控制器中注入工作单元是一个好主意,尝试将逻辑和事务从UI中分离出来 2) 是的,您可以在您的服务中注入UoW,最好是通过IoC容器注入构造函数。有些人将其设计为静态工厂,但我更喜欢将其用作构造

我的控制器使用2个或更多服务。反过来,我的服务构造并使用它们自己的工作类单元实例(具有对存储库的访问权)

我希望我的服务共享同一个工作单元实例,并使其可进行单元测试。我的问题是:

  • 我是否应该将工作单元和服务注入控制器
  • 我还需要将工作单元注入到我的服务中。哪里 我应该那样做吗?非常感谢你
  • 1) 我不认为在UI控制器中注入工作单元是一个好主意,尝试将逻辑和事务从UI中分离出来

    2) 是的,您可以在您的服务中注入UoW,最好是通过IoC容器注入构造函数。有些人将其设计为静态工厂,但我更喜欢将其用作构造函数中注入的参数

    public class MyService : IMyService
    {
      IUnitOfWork _unitOfWork;
    
      public MyService(IUnitOfWork uow)
      {
        _unitOfWork = uow;
      }
    
      public void DoSomeOperation(SampleParam param)
      {
        _unitOfWork.BeginTrx();
        //  do some work 
        _unitOfWork.Commit();
      }
    }
    
    或使用静态工厂

    public class MyService : IMyService
    {
      public void DoSomeOperation(SampleParam param)
      {
        using(UnitOfWork.Start())
        {
          //  do some work 
        }
      }
    }
    

    我喜欢Mohamed Abed的回答,我还没有得到足够的分数在他的帖子中添加评论,所以我只想指出,在这些情况下,您需要确保工作单元被标记为单个实例,否则它将不会在服务之间共享。

    我喜欢将DI与操作过滤器相结合,通过这种方式,容器可以管理工作单元的范围,但是begin/commit/rollback会自动为您调用,您不必在每个操作上都对它大惊小怪

    这有点棘手,因为通常情况下,actionfilters不会针对每个请求重新实例化,因此当您有一个确实希望针对每个请求(工作单元)的依赖项时,您需要发挥一些魔力

    下面是我如何使用Ninject和Ninject.Web.Mvc实现这一点

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
        public class UnitOfWorkAction : Attribute
        {
        }
    
        public class UnitOfWorkActionFilter : IActionFilter
        {
            private IUnitOfWork _unitOfWork;
    
            public UnitOfWorkActionFilter(IUnitOfWork unitOfWork)
            {
                _unitOfWork = unitOfWork;
            }
    
            public void OnActionExecuting(ActionExecutingContext filterContext)
            {
                _unitOfWork.Begin();
            }
    
            public void OnActionExecuted(ActionExecutedContext filterContext)
            {
                if (filterContext.Exception == null)
                    {
                        try
                        {
                            _unitOfWork.Commit();
                        }
                        catch
                        {
                            _unitOfWork.Rollback();
                            throw;
                        }
                    }
                    else
                    {
                        _unitOfWork.Rollback();
                    }
            }
        }
    
    然后配置在App_Start/NinjectMVC3.cs中应该如何使用该属性

    kernel.BindFilter<UnitOfWorkActionFilter>(FilterScope.Action, 0)
                    .WhenActionMethodHas<UnitOfWorkAction>();
    //also make sure your IUnitOfWork is bound per request, obviously
    

    另外值得注意的是,这种方法允许您将依赖项的构造函数注入到操作过滤器中,而不仅仅是属性注入,我非常喜欢这种方法。

    我在管理服务中的工作单元时遇到的问题与在存储库中管理工作单元时遇到的问题相同,也就是说,您现在无法轻松地将多个服务调用绑定到一个事务中,而失败会导致数据处于奇怪的状态。如果一个服务需要调用另一个服务,这将变得更加复杂。我认为最好的解决方案是将UoW的管理工作99%留给应用程序/ui层。另外1%需要对复杂流程进行细粒度控制,这很好,但这是个例外,不是标准。我同意布鲁克的观点。服务层应该是可重用的,并且与使用它的应用程序无关。当您将UoW放入服务层时,您也在为消费应用程序指定UoW范围。考虑一个桌面应用程序,它允许您为同一表单上的多个实体维护数据。当您单击“保存”时,应用程序会在提交UoW之前调用4或5种服务方法。例如,如果UoW位于服务层,那么在移动应用程序上编辑相同数据的较小子集的更精简的UI将无法重用服务层代码。
    [UnitOfWorkAction]
    public ActionResult SomeAction(int id)
    {
         //invoke your services here, and the uow will be automatically committed or rolled back when the action returns
     }