2

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

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

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

一切都被包装在一个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。

4

1 回答 1

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以指定给定站点地图节点是否可见。

于 2011-12-29T23:55:16.213 回答