2

在我正在构建的系统中,我使用命令模式执行所有可能的操作。我选择了CommandMessage和CommandHandler方法,将逻辑从数据中分离出来。 现在工作正常,但我遇到了问题 - 验证。在执行前验证命令

我该如何验证命令是否可以执行?

现在我每个命令都有一个CanExecute(ICommandExecutionContext context),使它负责确定它是否可以执行。然后在每个命令中查找一个ICommandExecutionContext,查看它是否属于正确的上下文类型,之后如果信息使该命令在该上下文中可执行。

所有内容都包含在ICommandService中,可以根据其名称,上下文和消息验证和执行命令。除此之外,它还发布关于命令执行的事件,并执行权限检查。

该问题源于UI(ASP.NET MVC 3应用程序)。我只想在每个视图中显示有效的命令,但我没有想出一个我真正喜欢的解决方案。目前我的控制器询问命令服务,一个命令是否能够执行,给出一个具体的情境,像这样:

var executionContext = new SystemCommandExecutionContext("SignInCommand", CurrentPrincial); 
var canExecute = _commandService.CanExecute(executionContext); 
/* Handle the result to enable or disable the action link */ 

对于其他类型的命令,即在具体的领域对象的作品,我用同样的命令服务方法,但一个不同的上下文,我通过域对象ID,像这样:

[HttpPost, Authorize, ValidateAntiForgeryToken /* etc. */] 
public ActionResult Delete(Guid id) 
{ 
    /* Note the additional object id in the context */ 
    var executionContext = new EntityCommandExecutionContext("DeletePersonCommand", CurrentPrincipal, id); 
    var canExecute = _commandService.CanExecute(executionContext); 

    if(canExecute) 
    { 
     var message = new DeletePersonCommandMessage(id); 
     var isValid = _commandService.IsValid(executionContext, message); 
     if(isValid) 
     { 
      var result = _commandService.Execute(executionContext, message); 
      /* More logic here... Not very DRY :(*/ 
     }    
    } 
} 

我猜上述现在好了,虽然不是非常干燥。 但我想完成的是根据CanExecute的结果禁用操作链接。

我该怎么做?

我决定在每个视图上“硬编码”所有的命令链接,所以我不必传递命令集合等等 - 这个路径太困难了(除非有人有一个聪明的想法;)

我目前的堆栈由NHibernate,Castle Windsor,ASP.NET MVC 3,AutoMapper组成。

回答

1

作为小记录,您的命令对象是那些被序列化并发送到(可能是远程)服务以由命令处理程序处理的命令对象,然而这不是GoF意义上的命令模式的实例,因为命令对象本身不提供执行方法。在这种情况下命令消息对象的目的是代表一个动作连同所需的参数。有些来源称它为可串行化的方法调用。消息对象不应该包含行为,只有数据,命令消息也不例外。这意味着确定给定命令是否可以在特定上下文中执行的过程应该由单独的服务来处理。此验证服务的具体实现取决于用于确定给定命令是否可以执行的标准。它可以基于一些上下文和命令的类型能够验证的命令:

interface ICommandValidationService 
{ 
    bool CanExecute(object context, Type commandType); 
} 

上下文对象应该是独立的正在执行的实际命令的。相反,它应该包含更多的全局上下文值,例如用户,用户权限等。命令执行的能力将使用此上下文来决定。基于命令的执行状态

禁用或隐藏操作链接可使用这样的视图模型来实现:

class ActionLinkViewModel 
{ 
     public string Name { get; set; } 
     public string Url { get; set; } 
     public bool Enabled { get; set; } 
} 

当启用值在控制器通过将ICommandValidationService分配。此外,您可以扩展MvcSiteMapProvider以指定给定的站点地图节点是否可见。

+0

这与我现在的情况差不多。我不确定你的意思是关于我的命令模式实现。你能详细说明一下吗?我相信(也许我不清楚),你忘了命令操作域对象?我不确定我如何能够向验证服务提供域信息的上下文? – Siewers 2011-12-30 09:59:10