简体   繁体   中英

How does FluentValidator determine what display name to use by default?

I'm working with FluentValidator in .NET Core. Everything is working beautifully for the most part, but I notice that when working with complex types, FluentValidator shows the full property name. For example, let's say I have a class named Address with Street, City, State, and Zip properties. Now let's say I have a form backed by a model property named Physical Address. If I make the street required, Fluent shows the following validation error:

'Physical Address. Street' must not be empty.

I prefer this to it just saying "Street" must not be empty because I might have multiple address fields on the page, so just displaying "Street" isn't specific enough. But I'd rather have it say:

'Physical Address Street' must not be empty. (with no period after the word address)

The example given by FluentValidation to globally override the display name is adding this in Startup.cs:

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

The override example works, but using this (minus the foo part) displays this validation error:

'Street' must not be empty. (the very thing I don't want because it's too generic)

What I need to know is what logic inside the lambda would produce the exact same result as the default behavior (ie Physical Address. Street , not just Street ). Once I know that, I can fix removing the period with a simple defaultValue.Replace(".","") . Thanks!

Update:

Much easier approach is to use ValidatorOptions.Global.PropertyNameResolver

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

Original Answer:

Prepared complete demo based on github sources

Note: I am using ValidatorOptions.Global.DisplayNameResolver instead of ValidatorOptions.DisplayNameResolver since it is obsolete and will be removed in future versions

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());
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM