diff --git a/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs b/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs index b1e57c4f4..921efa4fc 100644 --- a/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs +++ b/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs @@ -26,7 +26,6 @@ public class NameResolutionPluggabilityTester : IDisposable { var error = validator.Validate(new Person { Address = new Address() }).Errors.Single(); error.PropertyName.ShouldEqual("Address.Country"); - } [Fact] @@ -43,6 +42,36 @@ public class NameResolutionPluggabilityTester : IDisposable { } } + [Fact] + public void ShouldHaveValidationError_Should_support_custom_propertynameresolver_with_include_properties() { + try { + ValidatorOptions.Global.PropertyNameResolver = (type, prop, expr) => "foo"; + var validator = new TestValidator() { + v => v.RuleFor(x => x.Surname).NotNull() + }; + validator.TestValidate(new Person(), strategy => strategy.IncludeProperties(x => x.Surname)).ShouldHaveValidationErrorFor(x => x.Surname); + } + finally { + ValidatorOptions.Global.PropertyNameResolver = null; + } + } + + [Fact] + public void ShouldHaveValidationError_Should_support_custom_propertynameresolver_with_include_properties_and_nested_properties() { + try { + ValidatorOptions.Global.PropertyNameResolver = (type, prop, expr) => "foo"; + var validator = new TestValidator() { + v => v.RuleFor(x => x.Address.Line1).NotNull() + }; + validator.TestValidate(new Person { + Address = new Address() + }, strategy => strategy.IncludeProperties(x => x.Address.Line1)).ShouldHaveValidationErrorFor(x => x.Address.Line1); + } + finally { + ValidatorOptions.Global.PropertyNameResolver = null; + } + } + public void Dispose() { ValidatorOptions.Global.PropertyNameResolver = null; } diff --git a/src/FluentValidation/Internal/MemberNameValidatorSelector.cs b/src/FluentValidation/Internal/MemberNameValidatorSelector.cs index 60f1d7b3d..200522926 100644 --- a/src/FluentValidation/Internal/MemberNameValidatorSelector.cs +++ b/src/FluentValidation/Internal/MemberNameValidatorSelector.cs @@ -73,12 +73,12 @@ public class MemberNameValidatorSelector : IValidatorSelector { } private static string MemberFromExpression(Expression> expression) { - var chain = PropertyChain.FromExpression(expression); + var propertyName = ValidatorOptions.Global.PropertyNameResolver(typeof(T), expression.GetMember(), expression); - if (chain.Count == 0) { + if (string.IsNullOrEmpty(propertyName)) { throw new ArgumentException($"Expression '{expression}' does not specify a valid property or field."); } - return chain.ToString(); + return propertyName; } }