流畅的验证自定义验证规则

Evg*_*vin 11 asp.net-mvc fluentvalidation asp.net-mvc-3

我有模特:

[Validator(typeof(RegisterValidator))]
public class RegisterModel
{
    public string Name { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }

    public string ListOfCategoriess { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和模型验证器:

public class RegisterValidator:AbstractValidator<RegisterModel>
{
    public RegisterValidator(IUserService userService)
    {
        RuleFor(x => x.Name).NotEmpty().WithMessage("User name is required.");
        RuleFor(x => x.Email).NotEmpty().WithMessage("Email is required.");
        RuleFor(x => x.Email).EmailAddress().WithMessage("Invalid email format.");
        RuleFor(x => x.Password).NotEmpty().WithMessage("Password is required.");
        RuleFor(x => x.ConfirmPassword).NotEmpty().WithMessage("Please confirm your password.");
    }
}
Run Code Online (Sandbox Code Playgroud)

我有验证工厂,应该解决依赖:

public class WindsorValidatorFactory : ValidatorFactoryBase 
{
    private readonly IKernel kernel;

    public WindsorValidatorFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        if (validatorType == null)
            throw new Exception("Validator type not found.");
        return (IValidator) kernel.Resolve(validatorType);
    }
}
Run Code Online (Sandbox Code Playgroud)

我有IUserService,它有方法IsUsernameUnique(string name)和IsEmailUnique(字符串电子邮件)`并希望在我的验证器类中使用它(模型只有在具有唯一用户名和电子邮件时才有效).

  1. 如何使用我的服务进行验证?
  2. 是否可以使用不同的错误消息注册多个正则表达式规则?它会在客户端工作吗?(如果没有,如何为它创建自定义验证逻辑?)
  3. 在模型传递in action方法之前,服务器端的验证是否会自动工作,并且调用ModelState.IsValid属性就足够了,或者我需要做更多的事情? UPDATE
  4. 验证某些属性时是否可以访问模型的所有属性?(例如我想在注册时比较密码和ConfirmPassword)

Dar*_*rov 22

1)如何使用我的服务进行验证?

你可以使用Must规则:

RuleFor(x => x.Email)
    .NotEmpty()
    .WithMessage("Email is required.")
    .EmailAddress()
    .WithMessage("Invalid email format.")
    .Must(userService.IsEmailUnique)
    .WithMessage("Email already taken");
Run Code Online (Sandbox Code Playgroud)

2)是否可以使用不同的错误消息注册多个正则表达式规则?它会在客户端工作吗?(如果没有,如何为它创建自定义验证逻辑?)

不,每个属性只能有一种验证类型

如果没有,如何为它创建自定义验证逻辑?

您可以使用必须规则:

RuleFor(x => x.Password)
    .Must(password => SomeMethodContainingCustomLogicThatMustReturnBoolean(password))
    .WithMessage("Sorry password didn't satisfy the custom logic");
Run Code Online (Sandbox Code Playgroud)

3)服务器端的验证是否会在模型传递动作方法之前自动工作,并且它足以调用ModelState.IsValid属性,或者我需要做更多的事情?

是的,一点没错.您的控制器操作可能如下所示:

[HttpPost]
public ActionResult Register(RegisterModel model)
{
    if (!ModelState.IsValid)
    {
        // validation failed => redisplay the view so that the user
        // can fix his errors
        return View(model);
    }

    // at this stage the model is valid => process it
    ...
    return RedirectToAction("Success");
}
Run Code Online (Sandbox Code Playgroud)

更新:

4)在验证某些属性时是否可以访问模型的所有属性?(例如我想在注册时比较密码和ConfirmPassword)

当然是:

RuleFor(x => x.ConfirmPassword)
    .Equal(x => x.Password)
    .WithMessage("Passwords do not match");
Run Code Online (Sandbox Code Playgroud)

  • 对的,这是可能的.您可以使用`.Must`规则:`RuleFor(x => x.Password).Must((model,password)=> userService.AreEmailAndPasswordValid(model.Email,password)).WithMessage("无效的电子邮件+密码组合");`. (2认同)

Mov*_*GP0 12

一个更好的变体是使用RuleBuilderExtension:

public static class RuleBuilderExtensions
{
    public static IRuleBuilder<T, string> Password<T>(this IRuleBuilder<T, string> ruleBuilder, int minimumLength = 14)
    {
        var options = ruleBuilder
            .NotEmpty().WithMessage(ErrorMessages.PasswordEmpty)
            .MinimumLength(minimumLength).WithMessage(ErrorMessages.PasswordLength)
            .Matches("[A-Z]").WithMessage(ErrorMessages.PasswordUppercaseLetter)
            .Matches("[a-z]").WithMessage(ErrorMessages.PasswordLowercaseLetter)
            .Matches("[0-9]").WithMessage(ErrorMessages.PasswordDigit)
            .Matches("[^a-zA-Z0-9]").WithMessage(ErrorMessages.PasswordSpecialCharacter);
        return options;
    }
Run Code Online (Sandbox Code Playgroud)

这样使用起来很简单:

RuleFor(x => x.Password).Password();
Run Code Online (Sandbox Code Playgroud)