【问题标题】:How to process business rules when using Dependency Injection and Repository Pattern in Controller?在Controller中使用依赖注入和存储库模式时如何处理业务规则?
【发布时间】:2013-01-14 18:47:45
【问题描述】:

因此,在所有使用 MVC(或 Web API)的存储库模式的 DI 示例中,99% 的示例在控制器操作中显示了与下面类似的内容(省略了 _repository 的构造函数注入代码)。问题是假设不需要首先处理任何内容(如规则)并且立即开始持久性:

public ActionResult Create(Person person)
{
    if (ModelState.IsValid)
    {
      _repository.Add(person);
    }

    return View(person);
}

问题是,如果我需要在持久化person 对象之前在域层处理规则 怎么办?显然,我不在 Controller 中执行该逻辑,而是在域层中需要它。下面哪个选项更好:

选项 1: 将要在域/业务层调用的存储库上的所有持久性细节委托并从控制器中提取。更新后的代码如下所示:

if (ModelState.IsValid)
{
  using (busniessLogic = new MyApp.BusniessLogic(_repository))
  {
       busniessLogic.ProcessRulesAndSavePerson(person);
  }
}

领域层可能有这样的方法:

public void ProcessRulesAndSavePerson(Person person)
{
   //process some rules...

   if(rules = true)
   {
     //use injected repository to add now that rules have passed
     _repository.Add(person)
   }
}

选项 2: 在 Controller 中保持与现在相同,但只需在保存到存储库之前调用处理规则即可。更新后的代码如下:

if (ModelState.IsValid)
{
  using (busniessLogic = new MyApp.BusniessLogic())
  {           
       busniessLogic.ProcessRulesAboutPerson(person);
       _repository.Add(person)
  }
}

我也对其他想法持开放态度,但我倾向于选项 #1。我喜欢让 Controller 保持精简,然后将注入的 _repository 传递给需要它的层。

对此的任何帮助表示赞赏,谢谢!

【问题讨论】:

    标签: asp.net-mvc dependency-injection repository-pattern


    【解决方案1】:

    这两个选项都将创建对业务逻辑处理器的依赖,在使用 new 关键字时总是要小心,因为当你尝试对你的方法进行单元测试时,你几乎总是会遇到问题,这会打败依赖注入的目的。

    您最好创建一个处理复杂业务逻辑的服务并将其注入您的控制器。如果您的大部分逻辑都很复杂,我会跳过将存储库一起传递给控制器​​,而只依赖服务为我处理所有事情。

    控制器:

    public MyController(IPersonService personService) 
    {
        _personService = personService;
    }
    
    public ActionResult Create(Person person)
    {
        if (ModelState.IsValid)
           _personService.Create(person);
        else
           ......
    }
    

    人员服务:

    public PersonService(IPersonRepository repo) 
    {
        _repo = repo;
    }
    
    public int Create(Person person)
    {
        //businesslogic
        return _repo.Add(person);
    }
    

    【讨论】:

    • 服务层可以只是一个.dll对吗?这是否意味着我的所有服务/业务方法都必须由接口定义?我认为答案是“是”,否则我无法将实例正确地注入到 Controller 中?
    • @atconway 完全正确!无论如何你都想要一个接口,这样你就可以通过向控制器构造函数中注入一个模拟来轻松地测试你的控制器(这是我们首先使用 DI 的主要原因)
    • 我喜欢使用Service层;直到现在都避免了,但足够简单,并且阅读了很多次。所以这是我的层:UI (MVC)、服务层、模型/实体层、存储库。因此,如果我使用此设置,并且业务逻辑在我的服务层中,那么我的模型层实际上只是 DTO。在这种情况下,我使用的是贫血域模型吗?我应该将业务逻辑从服务层移动到模型层吗?
    • 关于这个话题有很多来回,我个人更喜欢智能模型(如果我的模型与其他模型交互,我通常会使用服务。没有正确的方式,就是对你有意义的任何方式。但你是对的,你可以使用服务,或者使用更智能的域模型!
    • 这对我来说很清楚。我将像之前看到的那样利用服务层作为存储库和域层的指挥,使其保持精简。我的域模型将在数据和行为方面保持稳健,因为我实际上最满意:martinfowler.com/bliki/AnemicDomainModel.html 感谢您的帮助!
    【解决方案2】:

    不一定是最好的方法,但这是我通常的做法:

    • IService(在您的情况下为业务逻辑)被注入到控制器(而不是 IRepository)中
    • 如果 ModelState 有效 => 控制器将调用 IService 中以模型为参数的方法
    • 如果需要,将 IRepository 注入到服务实例中。

    这使我能够: - 能够对提供 IService 模型的控制器进行单元测试。 - 让控制器不了解存储库和数据访问层。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多