在服务中使用UnitOfWork的哪种变体更合适?

时间:2015-11-10 19:38:41

标签: c# asp.net-mvc-4 architecture

美好的一天!

我的系统有N层架构:

  • DAL(数据访问层)(实体框架6,存储库, UnitOfWork)
  • BLL(商业逻辑层)
  • PL(表示层)(ASP.NET MVC 4)

问题如下:

UnitOfWork使用的哪种变体更合适?

第一个变体(特性的使用,在控制器ASP.NET MVC中显式调用Dispose()):

namespace MyApp.BLL.Services
{
    public class MyService
    {
    private UnitOfWork _uow { get; set; }

    public MyService()
    {
      _uow = new UnitOfWork();
    }

    public List<SomeDTO> SomeGetMethod()
    {
      IEnumerable<Entity> entities = _uow.SomeRepository.Get(x => x.Id==1);
      ...
      return ...
    }

    public void SomeSetMethod(int value)
    {
      _uow.SomeRepository.Insert(new Entity { Value = value });

      _uow.Commit(); // SaveChanges();
    }

    public Dispose()
    {
      _uow.Dispose();
    }
  }
}

第二个变体(使用块):

namespace MyApp.BLL.Services
{
    public class MyService
    {
    public List<SomeDTO> SomeGetMethod()
    {
      using(UnitOfWork uow = new UnitOfWork())
      {
        IEnumerable<Entity> entities = uow.SomeRepository.Get(x => x.Id==1);
      }
      ....
      return ...
    }

    public void SomeSetMethod(int value)
    {
      using(UnitOfWork uow = new UnitOfWork())
      {
        uow.SomeRepository.Insert(new Entity { Value = value });

        uow.Commit(); // SaveChanges();
      }
    }
  }
}

第二个问题:

例如,我们有一个服务,它负责系统中的消息模块工作 - IMessagesService,我们还有第二个服务,负责一些模块 - ISomeService。在服务ISomeService中创建方法的结果是必须在系统中发送消息。调用另一个IMessagesService的方法来发送消息是否正确?

示例:

public interface IMessagesService
{
  void Send(int userFrom, int userTo, string message);
  // other methods...
}

public class MessageService
{
  public void Send(int userFrom, int userTo, string message)
  {
    // some logic here
  }
}

public interface ISomeService
{
  void SomeMethod(int somevalue);
}

public class SomeService: ISomeService
{
  public void SomeMethod(int somevalue)
  {
    // some logic here

    // после необходимо отправить сообщение
    messageService = new MessageService();
    messageService.Send(1, 2, "some text");
  }
}

换句话说 - 从第二服务的一种服务方式调用是否正确?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我认为私有变量unitofwork是一种更好的方法,因为它倾向于更多地倾向于控制反转,但是没有注入控制,而对我来说使用块方法并不是在他们自己的服务中完成的。 单元工作对象应该注入,并在其他地方控制。 IMO单元工作模式的全部要点是封装事务范围。此事务范围应该能够跨越服务。良好的封装原则指导我们进行单一聚焦(SOLID)的原子服务。即在你的情况下,与消息有关的一切都应该在消息服务中,这是正确的。但正如您所见,由于这一原则,其他服务可能需要发送消息。所以是的,我认为一个服务调用另一个服务并不是不合理的,特别是如果有需要强制执行的业务规则的话。事实上,多个服务进入同一个存储库可能会做同样的事情,这违反了DRY IMO。  我还认为,如果发生故障,则不希望发送消息,或者如果消息发送失败则回滚第一个动作(可能是什么)。您当然可以测试这个(如果..然后..类型模式),并可能手动编写回滚代码(丑陋!)但是使用相同的单元工作包装所有正在使用的服务意味着您有一个回滚(并提交) )无论如何都要使用类型方法(特别是如果你使用的是ORM映射器,即实体框架),而且许多嵌入式if语句可能会让代码闻到IMO。

因此,您不会将单元工作注入服务中,因此您的事务范围仅限于其创建的服务。此外,还会使测试更加困难。所有这些问题都与我现在正在进行的另一个项目完全相同,它遵循相同的代码结构/方法,我将是第一个说,我还没有找到一个完美的方法,但我会接近它更像是这样的东西:

//Base service class to take the unit of work injection
public abstract class BaseService
    {
    private IUnitOfWork _uow { get; private set; }

    public BaseService(IUnitOfWork scope)
    {
      _uow = scope;
    }
}

然后是服务类实现

public class SomeService: BaseService, ISomeService
{
    public MyService(IUnitOfWork scope) : base(scope)
    {

    }
  public void SomeMethod(int somevalue)
  {

    //Do something in this service
    //code here.....

   //then do something in the next service, passing though 
    //the same unitof work

    messageService = new MessageService(_uow );
    messageService.Send(1, 2, "some text");
  }
}

这将控制单元工作(范围)的责任传递给调用者。在您的情况下,PL表示层,或者如果您愿意,为了便于测试另一个测试类。来自PL的东西:

//PL Controller that does something cool
public class BaseService : Controller
{

    public ActionResult DoSomething(int value)
    {
        using(IUnitOfWork scope = new UnitOfWork())
        {
            ISomeService theService = new SomeService(scope);
            theService.SomeMethod(value);
        }
        ...con
    }

}

我实际上在PL和BLL之间放置了另一层来控制范围,如果你愿意的话,Dependancy会注入服务,就像一个单元工作控制器。

无论如何我的两分钱