执行前验证命令

时间:2011-12-29 10:15:51

标签: asp.net-mvc-3 design-patterns inversion-of-control command-pattern

在我正在构建的系统中,我使用命令模式执行所有可能的操作。我选择了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 个答案:

答案 0 :(得分: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以指定给定的站点地图节点是否可见。