【发布时间】:2014-06-22 19:41:23
【问题描述】:
我正在创建一个试图避免Fat Controller 气味的 ASP.NET MVC 应用程序。我这样做是通过使控制器方法简单地将轻量级命令发送到命令总线,然后由命令处理程序接收。命令处理程序在域模型上执行命令,进而创建持久的状态更改事件。
我这样做是为了尝试摆脱“从存储库中获取 X,对其进行更改并将其放回原处”的 CRUD 模型,从 Web 应用程序中删除所有特定于领域的知识,并允许用户的意图直接与域模型通信。
因此,假设 Contact 聚合的组成如下(为简洁起见,我省略了除了一个 setter 方法之外的所有方法)。
public class Contact {
private Address _homeAddress;
public Address HomeAddress {
get { return _homeAddress; }
set {
if(newHomeAddress.Equals(_homeAddress)) return;
_homeAddress = newHomeAddress;
AddEvent(new HomeAddressChanged(Id, _homeAddress));
}
}
public Address WorkAddress { get; set; }
public PhoneNumber PhoneNumber { get; set; }
public EmailAddress EmailAddress { get; set; }
}
执行 HomeAddress 更改的命令处理程序如下所示。
public class ChangeHomeAddressCommandHandler : IHandleCommand<ChangeHomeAddressCommand>
{
private IRepository<Contact> _repo;
public ChangeHomeAddressCommandHandler(IRepository<Contact> repo)
{
_repo = repo;
}
public void Execute(ChangeHomeAddressCommand command)
{
var toEdit = _repo.One(command.Id);
toEdit.HomeAddress = command.NewHomeAddress;
_repo.CommitChanges(toEdit);
}
}
我的问题是,用户提交的表单需要允许编辑整个联系人,即所有相关的地址、电话号码等),这意味着每个属性状态都需要一个命令和一个处理程序改变。
这些处理程序中的每一个都需要加载聚合、进行更改然后提交更改。因此,即使您不更改所有属性,命令处理程序仍然需要四次加载和构建 Contact 聚合,这是不必要的昂贵。
我已经考虑了一些选择...
可以将每个可能的子命令(即单独的 ChangeHomeAddressCommand)的实例添加到其中的“宏”命令(可能称为 EditContactCommand)。宏命令加载聚合并将其传递给子命令并在 dispose 时提交更改。
使 UI 更加“以任务为中心”。编辑页面不是一个结构化的文本框集合来收集输入,而是使用带有“更改”按钮的标签,该按钮调用一个模式对话框。当模态对话框确定时,将 AJAX 回传到控制器,控制器反过来总线命令。或者实际上,构建仅公开联系人聚合的某些方面的较小页面。您只会更改实际更改的内容,并且更改可以在没有大的“保存”式提交的情况下发生。 (我不确定用户是否会穿这个,因为他们似乎喜欢他们的文本框海洋!)
我将不胜感激任何建议、经验和智慧。谢谢。
【问题讨论】:
标签: asp.net-mvc asp.net-mvc-4 domain-driven-design cqrs