c# - 使用 MVC 在 CQRS 中应该在哪里进行验证?

标签 c# asp.net-mvc

这是我创建新用户的 post 方法:

[HttpPost]
public ActionResult CreateUser(CreateUserViewModel createUserViewModel)
{
    CreateSystemUserCommand createSystemUserCommand = new CreateSystemUserCommand()
    {
        Firstname = createUserViewModel.Forename,
        Surname = createUserViewModel.Surname,
        Username = createUserViewModel.Username,
        Password = createUserViewModel.Password
    };

    CreateSystemUserCommandHandler handler = new CreateSystemUserCommandHandler();

    handler.Execute(createSystemUserCommand);

    return RedirectToAction("ViewUsers");
}

已经对 View 模型、必填字段等进行了一些验证,因此 UI 将对其进行验证。

但是我想知道如何在服务器端进行。

我应该创建一个方法 createSystemUserCommand.Validate();

或在 handler.Execute() 之前,执行 handler.Validate()

我应该如何将这些错误转化为 ModelState?我猜 CQRS 没有与 MVC 连接,因此返回特定的模型错误是没有意义的。

欢迎对此提出任何想法。我的直觉是执行 handler.Validate,因为它将验证逻辑保留在一个类中,感觉不错,但我愿意接受建议。

最佳答案

这里有两种您可能需要的验证类型:

  • 一个是简单的 ModelState 验证,确保必填字段不会丢失,int 是一个 int 等等。为此,使用数据注释属性就可以解决问题。

  • 第二种类型是业务逻辑验证 - 可能需要访问数据库或运行其他一些验证逻辑以确保数据完整性不受影响。这种类型的验证将在命令级别进行。 最好的方法是遵循 decorator pattern - 将您的实际处理程序包装在验证处理程序中:

    public class ValidationCommandHandlerDecorator<TCommand, TResult>
        : ICommandHandler<TCommand, TResult>
        where TCommand : ICommand<TResult>
    {
        private readonly ICommandHandler<TCommand, TResult> decorated;
    
        public ValidationCommandHandlerDecorator(ICommandHandler<TCommand, TResult> decorated)
        {
            this.decorated = decorated;
        }
    
        [DebuggerStepThrough]
        public TResult Handle(TCommand command)
        {
            var validationContext = new ValidationContext(command, null, null);
            Validator.ValidateObject(command, validationContext, validateAllProperties: true);
    
            return this.decorated.Handle(command);
        }
    }
    

    验证器的一个例子是:

    public class SomeCustomLogicValidator : IValidator {
    
        void IValidator.ValidateObject(object instance) {
            var context = new ValidationContext(instance, null, null);
    
            // Throws an exception when instance is invalid.
            Validator.ValidateObject(instance, context, validateAllProperties: true);
        }
    }       
    

    然后注册为:

    // using SimpleInjector.Extensions;
    container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ValidationCommandHandlerDecorator<>));
    

    您可以根据需要包装任意数量的装饰器,甚至可以使其特定于谓词(具体语法取决于您使用的 DI 框架):

    // another decorator
    container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(TransactionCommandHandlerDecorator<>));
    
    // specific decorator
    container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(AccessValidationCommandHandlerDecorator<>),
    context => !context.ImplementationType.Namespace.EndsWith("Admins"));
    

我的例子使用了一个 DI 框架,它使事情变得更简单,但这个想法也可以在不使用任何 DI 容器的情况下进行扩展。

关于c# - 使用 MVC 在 CQRS 中应该在哪里进行验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26101304/

相关文章:

c# - 在 WPF 中的 MediaElement 顶部呈现按钮

javascript - 如何使用JQuery正确获取跨域的xml

asp.net-mvc - asp.net mvc模型数据库变更

html - 在 Razor View 中的三元 if 运算符内分配变量

c# - 在 Dapper.NET 中调整 CommandTimeout?

c# - ASP.NET Identity - 匿名配置文件

c# - 如何使用ServiceStack实现删除服务调用

c# - 如何在 asp.net 中流式传输视频内容?

asp.net-mvc - asp mvc 与 nvelocity?

javascript - 使用js脚本后无法提交html表单