这是我创建新用户的 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/