MVC DDD:将存储库与控制器中的服务一起使用是否可以?

时间:2010-08-26 12:23:52

标签: asp.net-mvc model-view-controller architecture domain-driven-design

在服务代码中的大部分时间我会有这样的东西:

public SomeService : ISomeService
{
    ISomeRepository someRepository;
    public Do(int id)
    {
        someRepository.Do(id);
    }
}

所以它有点多余

所以我开始直接在控制器中使用存储库

这样可以吗?是否有一些架构正在这样做?

5 个答案:

答案 0 :(得分:5)

  

你失去了在两者之间建立业务逻辑的能力。

我不同意这一点。

如果业务逻辑应该在哪里 - 在域模型中,那么在控制器中调用repo(或者更好 - 使用模型绑定器)来获取聚合根和调用方法就好了。

如果涉及的技术细节太多会导致控制器混乱,则应使用应用程序服务。


  

我看到有几个人提到最近使用模型绑定器调用回购。这个疯狂的想法来自哪里?

我相信我们在这里谈论两件不同的事情。我怀疑你的'模型绑定器'意味着同时使用模型作为视图模型,并将UI中的更改值直接绑定到它(这本身并不是坏事,在某些情况下我会走这条路)。

我的'模型绑定器'是一个实现'IModelBinder'的类,它在构造函数中占用存储库(因为我们需要使用一些基本组合进行缓存,因此可以扩展)并在操作之前使用它调用以检索聚合根并将int idGuid idstring slugwhatever操作参数替换为真实域对象。将它与输入视图模型参数相结合,可以让我们编写更少的代码。像这样:

public ActionResult ChangeCustomerAddress
 (Customer c, ChangeCustomerAddressInput inp){
  c.ChangeCustomerAddress(inp.NewAddress);
  return RedirectToAction("Details", new{inp.Id});
}

在我的实际代码中,它有点复杂,因为它包含ModelState验证和一些可能从域模型内部抛出的异常处理(提取到Controller扩展方法中以便重用)。但不多。到目前为止 - 最长的控制器动作长约10行。

你可以看到工作实现(非常复杂和(对我来说)不必要的复杂)here

  

您是刚刚使用Linq To Sql做CRUD应用程序还是尝试使用真实域逻辑?

正如你可以(希望)看到的那样,这种方法实际上几乎迫使我们转向task based应用而不是基于CRUD的应用。

  

通过在服务层中进行所有数据访问并使用IOC,您可以获得AOP的许多好处,例如无形缓存,事务管理以及我​​无法想象您使用模型绑定器的组件的简单组合。

...并且拥有新的抽象层邀请我们将基础架构与域逻辑混合在一起并失去域模型的隔离。

  

请赐教。

我不确定我是否这样做过。我不认为我自己开悟了。 :)


Here是我当前的模型绑定器基类。 Here's我当前项目中的一个控制器操作。 here's“缺乏”业务逻辑。

答案 1 :(得分:2)

如果在控制器中使用存储库,则直接从数据层到表示层。你失去了在两者之间拥有业务逻辑的能力。

现在,如果您说您只需要在需要业务逻辑时使用服务,并在其他地方使用存储库,那么您的代码将变成一场噩梦。表示层现在正在调用业务层和数据层,并且您没有很好的关注点分离。

我总是走这条路:Repositories -> Services -> UI。只要您认为自己不需要业务层,需求就会发生变化,您将不得不重写所有内容。

答案 2 :(得分:1)

这是事情。

“业务逻辑”应该驻留在您的实体和值对象中。

存储库仅处理AggregateRoots。因此,直接在您的控制器中使用您的存储库有点像您将该操作视为您的“服务”。此外,由于您的AggregateRoot只能通过其ID引用其他AR,因此您可能需要调用一个以上的repo。它真的很快变得讨厌。

如果您要获得服务,请确保公开POCO而不是实际的AggregateRoot及其成员。

除了创建,检索,更新和删除内容之外,您的repo不应该执行任何操作。您可能会根据具体情况进行一些自定义检索,但这就是它。因此,在您的仓库中使用与您的服务中的一个匹配的方法......代码闻到了那里。

您的服务是面向API的。考虑一下......如果你要将该服务打包成.dll供我使用,你将如何以一种易于我知道你的服务可以做什么的方式创建你的方法? Service.Update(对象)没有多大意义。

我甚至没有谈到CQRS ......事情变得更加有趣。

您的Web Api只是您服务的客户。您的服务可以被其他服务使用,对吧?所以,想一想。您很可能需要一个服务来封装AggregateRoots上的操作,通常是通过创建它们,或从repo中检索它们,对它做一些事情,然后返回结果。一般

有道理吗?

答案 3 :(得分:0)

我自己的 DDD / MVC的粗略做法:

  • 控制器是特定于应用程序的,因此它们应该只包含特定于应用程序的方法,并调用服务方法。
  • 所有公共服务方法通常都是原子事务或查询
  • 仅服务实例化&调用存储库
  • 我的域定义了一个IContextFactory和一个IContext(大量漏洞抽象,因为IContext成员是IDBSet)
  • 每个应用程序都有一个Composition Root,主要是实例化一个Context Factory传递给服务(你可以使用DI容器,但不是什么大不了的事)

这迫使我保留我的业务代码和数据访问权限。我觉得这是一个很好的训练,因为当我不遵循上述规定时,我是多么宽松!

答案 4 :(得分:-2)

即使使用“富域模型”,您仍然需要域服务来处理涉及多个实体的业务逻辑。我没有看过没有一些业务逻辑的CRUD,但是在简单的示例代码中。我总是喜欢马丁的路线来保持我的代码直截了当。