使用动态消息进行流畅的验证

时间:2013-04-09 13:22:47

标签: asp.net-mvc asp.net-mvc-4 fluentvalidation fluentvalidation-2.0

我正在尝试使用流畅的验证库中的动态消息构建自定义验证。

例如:

public class CreateProcessValidator : AbstractValidator<CreateProcessVM>
{
    public CreateProcessValidator()
    {
        RuleFor(x => x.ProcessFile).Must((x,e) => IsProcessFileValid(x.ProcessFile))).WithMessage("Parse failed with error : {0}");        
    }

    public bool IsProcessFileValid(HttpPostedFileBase file)
    {
        var errorMessage = "..."  // pass result to validaton message ?
        // logic
        return false;
    }
}

这里有解决方法如何传递验证结果吗?

由于

4 个答案:

答案 0 :(得分:17)

你尝试过这样的事吗?

public class IsProcessFileValid : PropertyValidator
{
    public IsProcessFileValid(): base("{ValidationMessage}") {}

    protected override IsValid(PropertyValidatorContext context)
    {
        if (!IsProcessFileValid1(context))
            context.MessageFormatter.AppendArgument("ValidationMessage",
                "Custom validation message #1");

        if (!IsProcessFileValid2(context))
            context.MessageFormatter.AppendArgument("ValidationMessage",
                "Custom validation message #2");

        // ...etc

        return true;
    }

    private bool IsProcessFileValid1(PropertyValidatorContext context)
    {
        // logic
        return false;
    }

    private bool IsProcessFileValid2(PropertyValidatorContext context)
    {
        // logic
        return false;
    }

    // ...etc
}

使用扩展方法:

public static class IsProcessFileValidExtensions
{
    public static IRuleBuilderOptions<T, object> MustBeValidProcessFile<T>
        (this IRuleBuilder<T, object> ruleBuilder)
    {
        return ruleBuilder.SetValidator(new IsProcessFileValid());
    }

}

...然后在没有自定义WithMessage的情况下使用它:

public CreateProcessValidator()
{
    RuleFor(x => x.ProcessFile).MustBeValidProcessFile();        
}

通过创建自定义PropertyValidator,您可以在该类中封装默认验证消息并使其动态化。但是,在声明.WithMessage时,您不得使用RuleFor扩展名,因为这会覆盖您在PropertyValidator内直接自定义的默认验证邮件。

答案 1 :(得分:2)

没有办法做到这一点。我会将您当前使用的复杂验证方法拆分为较小的方法(IsProcessFileValid1,IsProcessFileValid2,IsProcessFileValid3,...),以便您可以对错误消息进行更细粒度的控制。此外,每种方法都只负责验证一次使它们更可重复使用(单一责任):

RuleFor(x => x.ProcessFile)
    .Must(IsProcessFileValid1)
    .WithMessage("Message 1")
    .Must(IsProcessFileValid2)
    .WithMessage("Message 2")
    .Must(IsProcessFileValid3)
    .WithMessage("Message 3");

另请注意我如何简化lambda,因为该方法可以直接作为参数传递给Must

答案 2 :(得分:0)

这是我解决的方法。经过FluentValidation v8.5.0测试

class EmptyValidationMessage : IStringSource
{
    public string ResourceName => null;

    public Type ResourceType => null;

    public string GetString(IValidationContext context)
    {
        return string.Empty;
    }

    public static readonly EmptyValidationMessage Instance = new EmptyValidationMessage();
}

public class MyPropValidator : PropertyValidator
{
    public MyPropValidator() : base(EmptyValidationMessage.Instance)
    {
    }

    protected override bool IsValid(PropertyValidatorContext context)
    {
        // if not valid

        Options.ErrorMessageSource = new StaticStringSource("my message");

        // you can do LanguageStringSource, LazyStringSource, LocalizedStringSource, etc

        // example with localized string (https://github.com/clearwaterstream/LocalizedString.FluentValidation)

        Options.ErrorMessageSource = new LocalizedStringSource("my message").InFrench("moi message");

        return false;
    }
}

答案 3 :(得分:0)

在尝试将异常消息插入WithMessage()时遇到了相同的问题。 它使用以Func<T, string> messageProvider作为参数的方法重载来工作。

以下是张贴者示例中提供的解决方案(工作代码,FluentValidation v 9.1):

public class CreateProcessVM
{
    public object ProcessFile { get; set; }
}

public class CreateProcessValidator : AbstractValidator<CreateProcessVM>
{
    public CreateProcessValidator()
    {
        var message = "Something went wrong.";
        RuleFor(x => x.ProcessFile)
            .Must((x, e) => IsProcessFileValid(x.ProcessFile, out message))
            // .WithMessage(message); will NOT work
            .WithMessage(x => message); //Func<CreateProcessVM, string> as parameter
    }

    public bool IsProcessFileValid(object file, out string errorMessage)
    {
        errorMessage = string.Empty;
        try
        {
            Validate(file);
            return true;
        }
        catch (InvalidOperationException e)
        {
            errorMessage = e.Message;
            return false;
        }
    }

    private void Validate(object file)
    {
        throw new InvalidOperationException("File of type .custom is not allowed.");
    }
}

还有一个测试,证明我们确实在错误消息中得到了异常消息:

[Fact]
public void Test()
{
    var validator = new CreateProcessValidator();
    var result = validator.Validate(new CreateProcessVM());
    Assert.False(result.IsValid);
    Assert.Equal("File of type .custom is not allowed.", result.Errors[0].ErrorMessage);
}