【问题标题】:How does FluentValidator determine what display name to use by default?FluentValidator 如何确定默认使用的显示名称?
【发布时间】:2020-10-16 17:23:08
【问题描述】:

我正在使用 .NET Core 中的 FluentValidator。在大多数情况下,一切都运行良好,但我注意到在处理复杂类型时,FluentValidator 会显示完整的属性名称。例如,假设我有一个名为 Address 的类,其中包含 Street、City、State 和 Zip 属性。现在假设我有一个由名为 Physical Address 的模型属性支持的表单。如果我要求街道,Fluent 会显示以下验证错误:

'Physical Address. Street' must not be empty.

我更喜欢它只是说“街道”不能为空,因为页面上可能有多个地址字段,因此仅显示“街道”还不够具体。但我宁愿说:

'Physical Address Street' must not be empty.(字地址后无句点)

FluentValidation 给出的全局覆盖显示名称的示例是在 Startup.cs 中添加:

ValidatorOptions.DisplayNameResolver = (type, member, expression) => {
  if(member != null) {
     return member.Name + "Foo";
  }
  return null;
};

覆盖示例有效,但使用此(减去 foo 部分)会显示此验证错误:

'Street' must not be empty.(我不想要的东西,因为它太通用了)

我需要知道的是 lambda 中的哪些逻辑会产生与默认行为完全相同的结果(即 Physical Address. Street,而不仅仅是 Street)。一旦知道这一点,我就可以使用简单的defaultValue.Replace(".","") 来修复删除句点。谢谢!

【问题讨论】:

    标签: c# validation .net-core fluentvalidation fluentvalidation-2.0


    【解决方案1】:

    更新:

    更简单的方法是使用ValidatorOptions.Global.PropertyNameResolver

    ValidatorOptions.Global.DisplayNameResolver = (type, memberInfo, expression) =>
        ValidatorOptions.Global.PropertyNameResolver(type, memberInfo, expression).SplitPascalCase();
    

    原答案:

    基于github sources准备完整的demo

    注意:我使用的是ValidatorOptions.Global.DisplayNameResolver 而不是ValidatorOptions.DisplayNameResolver,因为它已过时,将在未来的版本中删除

    using FluentValidation;
    using FluentValidation.Internal;
    using System;
    using System.Linq.Expressions;
    using System.Reflection;
    
    namespace ConsoleApp4
    {
        public class Root
        {
            public PhysicalAddress PhysicalAddress { get; set; }
                = new PhysicalAddress();
        }
    
        public class PhysicalAddress
        {
            public string Street { get; set; }
        }
    
        public class RootValidator : AbstractValidator<Root>
        {
            public RootValidator()
            {
                RuleFor(x => x.PhysicalAddress.Street).NotNull();
            }
        }
    
        class Program
        {
            static string DefaultPropertyNameResolver(Type type, MemberInfo memberInfo, LambdaExpression expression)
            {
                if (expression != null)
                {
                    var chain = PropertyChain.FromExpression(expression);
                    if (chain.Count > 0) return chain.ToString();
                }
    
                return memberInfo?.Name;
            }
    
            static void Main(string[] args)
            {
                ValidatorOptions.Global.DisplayNameResolver = (type, memberInfo, expression) => 
                    DefaultPropertyNameResolver(type, memberInfo, expression).SplitPascalCase();
    
                var res = new RootValidator().Validate(new Root());
            }
        }
    }
    

    【讨论】:

    • 是的,没问题。我选择了速记解决方案,因为它确实更容易,而且我希望尽可能保持我的代码简短和干净:) 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 2013-07-29
    • 2011-07-15
    • 2021-11-03
    • 1970-01-01
    • 2020-12-17
    相关资源
    最近更新 更多