流利的验证与动态消息

10

我希望你能协助翻译关于IT技术的内容。这段内容涉及fluent validation库中构建包含动态消息的自定义验证。

举例来说:

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个回答

20

你尝试过类似这样的东西吗?

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,可以在该类中封装默认的验证消息并使其动态化。但是,在声明RuleFor时不要使用.WithMessage扩展,因为这会覆盖您直接定制的默认验证消息。PropertyValidator中。请保留所有HTML标记。

谢谢你的回答,我现在有点忙,但下周我会尝试。 - Mennion
你有机会试过这个吗?我有一种感觉它会起作用。 - danludwig
谢谢 - 正是我所需要的。对于我来说特别有用,可以验证类型为ZipFile(DotNetZip)的HttpPostedFileBase。 - dev'd

3
面对相同的问题,我尝试将异常消息插入到 WithMessage() 中。通过使用接受 Func<T, string> messageProvider 参数的方法重载,它已经起作用了。
以下是海报示例中提出的解决方案(有效代码,FluentValidation 版本为 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);
}

1

以下是我的解决方法。测试使用的 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;
    }
}

0

无法这样做。我建议将您当前拥有的复杂验证方法分解为较小的方法(如IsProcessFileValid1、IsProcessFileValid2、IsProcessFileValid3等),以便您可以更细粒度地控制错误消息。此外,每个方法只负责验证一个关注点,使它们更具可重用性(单一职责):

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

此外,请注意我简化了lambda表达式,因为该方法可以直接作为参数传递给Must

是的,拆分方法是我的第一个想法,但这并不能解决我的问题,因为在其中一个小方法中,我正在尝试根据XSD验证XML文件,并需要将结果传递给用户... - Mennion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接