【问题标题】:One Message for rule chain?规则链的一条消息?
【发布时间】:2016-02-19 19:12:19
【问题描述】:

我遇到了 FluentValidation 问题,我想显示一条消息,而不管给定链中的验证错误如何。例如,我为下面的一个属性定义了一个验证链。我希望对链进行评估,任何失败都会导致下面的WithMessage() 调用中定义的消息。但是,它似乎是短路的,并且仅针对遇到的第一个错误显示 FluentValidation 默认错误消息。见以下代码:

RuleFor(s => s.ProposalDetail.AgeMin).NotNull()
        .GreaterThanOrEqualTo(1)
        .LessThanOrEqualTo(99)
        .WithMessage("Minimum Age entry is required and must range from 1 to 99 years.");

发生的情况是 AgeMin 属性为空,因此第一个 NotNull() 检查失败,验证消息显示“'提案详细信息。Age Min' 不能为空。” Proposal Detail 是封装视图模型的名称。 我尝试将整个验证器的 CascadeMode 设置为 CascadeMode.Continue,但没有任何效果。

如何为一个属性验证链完成一条消息?

【问题讨论】:

  • With the above code, the default validation message is returned, rather than the custom message at the end 声明的默认消息在哪里..?你能发布所有相关代码吗..你也检查了fluentvalidation for .NET Documentation /Examples
  • 是的,我已经搜索了文档,但没有找到类似的示例。我想我必须使用一个使用Must() 的规则来封装所有规则以完成我想要做的事情。我原以为这是一个简单的用例。默认的 FluentValidation 消息返回 'Proposal Detail. Age Min' must not be empty,因为 NotNull() 是链中的第一个调用。我尝试为验证器设置CascadeMode = CascadeMode.Continue,但没有效果。
  • 请提供一个minimal reproducible example 来证明您的问题。它必须是我们可以运行的可编译代码。

标签: c# .net fluentvalidation


【解决方案1】:

更新 4
我找到了一个更简单的解决方案,它适用于使用 Configure 方法的任何版本,因此不再需要我原来的“扩展方法”方法

using FluentValidation;
using FluentValidation.Results;
using System;
using System.Linq;

namespace ConsoleApplication9
{
    class Program
    {
        static void Main(string[] args)
        {

            Customer customer = new Customer() { };
            CustomerValidator validator = new CustomerValidator();
            ValidationResult results = validator.Validate(customer);
            Console.WriteLine(results.Errors.First().ErrorMessage);
            Console.ReadLine();
        }
    }
    public class CustomerValidator : AbstractValidator<Customer>
    {

        public CustomerValidator()
        {
            RuleFor(s => s.Id).NotNull()
                .GreaterThanOrEqualTo(1)
                .LessThanOrEqualTo(99)
                .Configure(rule => rule.MessageBuilder = _ => "Minimum Age entry is required and must range from 1 to 99 years.");

        }

    }

    public class Customer { public int? Id { get; set; } }
}

原答案:它可以工作到版本 9,但它比上面的更复杂
你可以用一个简单的扩展方法完成你想要的

using FluentValidation;
using FluentValidation.Internal;
using FluentValidation.Resources;
using FluentValidation.Results;
using System;
using System.Linq;

namespace ConsoleApplication9
{
    class Program
    {
        static void Main(string[] args)
        {

            Customer customer = new Customer() { };
            CustomerValidator validator = new CustomerValidator();
            ValidationResult results = validator.Validate(customer);
            Console.WriteLine(results.Errors.First().ErrorMessage);
            Console.ReadLine();
        }
    }
    public class CustomerValidator : AbstractValidator<Customer>
    {
        public CustomerValidator()
        {

            RuleFor(s => s.Id).NotNull()
                          .GreaterThanOrEqualTo(1)
                          .LessThanOrEqualTo(99)
                          .WithGlobalMessage("Minimum Age entry is required and must range from 1 to 99 years.");
        }

    }

    public class Customer { public int? Id { get; set; } }

    public static class MyExtentions
    {
        public static IRuleBuilderOptions<T, TProperty> WithGlobalMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage)
        {
            foreach (var item in (rule as RuleBuilder<T, TProperty>).Rule.Validators)
                item.Options.ErrorMessageSource=new StaticStringSource(errorMessage);
        
            return rule;
        }
    }
}

以下适用于任何版本,但由于它使用Must 方法,它不是很干净,您会错过流畅界面的感觉。

using FluentValidation;
using FluentValidation.Results;
using System;
using System.Linq;

namespace ConsoleApplication9
{
    class Program
    {
        static void Main(string[] args)
        {
            Customer customer = new Customer() { };
            CustomerValidator validator = new CustomerValidator();
            ValidationResult results = validator.Validate(customer);
            Console.WriteLine(results.Errors.First().ErrorMessage);
            Console.ReadLine();
        }
    }
    public class CustomerValidator : AbstractValidator<Customer>
    {
        public CustomerValidator()
        {
            RuleFor(x => x)
                .Must(x => x.Id != null && x.Id >= 1 && x.Id <= 99)
                .WithMessage("Minimum Age entry is required and must range from 1 to 99 years.");
        }
    }
    public class Customer { public int? Id { get; set; } }
}

更新 3:(2019 年 4 月 4 日 7 日) 在 FluentValidation v8.2.2 中,IRuleBuilderOptions 接口不再可以直接访问IRuleBuilderOptions.ErrorMessageSource 属性,而是应该使用:IRuleBuilderOptions.Options.ErrorMessageSource

【讨论】:

  • 您的更新 2 是正确答案。我打算研究一个类似的解决方案,但你打败了我。
  • @devuxer 我只留下了以前的用于教育目的
  • @GeorgeVovos 这是解决此问题的出色、优雅的解决方案。我已确认该解决方案按预期执行。谢谢!
  • @MRK 我今晚或明天会检查它
  • @MRK 我找到了适用于所有版本的更好解决方案
【解决方案2】:

最直接的解决方案是将消息设置为一个变量,并在每个规则之后应用相同的消息:

var message = "Minimum Age entry is required and must range from 1 to 99 years.";
RuleFor(s => s.ProposalDetail.AgeMin)
    .NotNull()
        .WithMessage(message)
    .GreaterThanOrEqualTo(1)
        .WithMessage(message)
     .LessThanOrEqualTo(99)
        .WithMessage(message);

【讨论】:

  • 在我看到 George 的编辑之前,我实际上一直在使用这个解决方案。这两种方法都是可行的,但我喜欢 George 解决方案的简洁性。
  • 当你需要为不同的验证规则分配不同的消息时,可以使用这种方法。
【解决方案3】:

替换 ErrorMessageSource 的过时属性分配并使用波纹管代替 FluentValidation 版本 >= 9.x

    public static class ValidatorExtensions
    {
        public static IRuleBuilderOptions<T, TProperty> WithGlobalMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage)
        {
            var rules = rule as RuleBuilder<T, TProperty>;
            foreach (var item in rules.Rule.Validators)
            {
                item.Options.SetErrorMessage(errorMessage);
            }

            return rule;
        }
    }

【讨论】:

    猜你喜欢
    • 2018-12-26
    • 1970-01-01
    • 2017-07-08
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多