From a51b01c2fafa6af3ab6e2377372aaee8d1aa2d38 Mon Sep 17 00:00:00 2001 From: Sergei Valko Date: Wed, 7 Sep 2022 21:25:54 +0300 Subject: [PATCH 1/3] add property resolver for include properties --- .../NameResolutionPluggabilityTester.cs | 14 ++++++++++++++ .../Internal/MemberNameValidatorSelector.cs | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs b/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs index b1e57c4f4..61543def7 100644 --- a/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs +++ b/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs @@ -43,6 +43,20 @@ 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; + } + } + public void Dispose() { ValidatorOptions.Global.PropertyNameResolver = null; } diff --git a/src/FluentValidation/Internal/MemberNameValidatorSelector.cs b/src/FluentValidation/Internal/MemberNameValidatorSelector.cs index 60f1d7b3d..5166932b0 100644 --- a/src/FluentValidation/Internal/MemberNameValidatorSelector.cs +++ b/src/FluentValidation/Internal/MemberNameValidatorSelector.cs @@ -79,6 +79,7 @@ public class MemberNameValidatorSelector : IValidatorSelector { throw new ArgumentException($"Expression '{expression}' does not specify a valid property or field."); } - return chain.ToString(); + var propertyName = ValidatorOptions.Global.PropertyNameResolver(typeof(T), expression.GetMember(), expression); + return propertyName; } } From 4a4f3e6e84f5dcd4870533e44c6eeab1658e0c02 Mon Sep 17 00:00:00 2001 From: Sergei Valko Date: Wed, 7 Sep 2022 23:34:17 +0300 Subject: [PATCH 2/3] added tests for nested properties --- .../NameResolutionPluggabilityTester.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs b/src/FluentValidation.Tests/NameResolutionPluggabilityTester.cs index 61543def7..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] @@ -50,7 +49,23 @@ public class NameResolutionPluggabilityTester : IDisposable { 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); + 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; From e2d878785c99a0540b454ff187dd7f1e7630bd8d Mon Sep 17 00:00:00 2001 From: sergeivalko Date: Sun, 11 Sep 2022 09:36:14 +0300 Subject: [PATCH 3/3] refactoring --- src/FluentValidation/Internal/MemberNameValidatorSelector.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/FluentValidation/Internal/MemberNameValidatorSelector.cs b/src/FluentValidation/Internal/MemberNameValidatorSelector.cs index 5166932b0..200522926 100644 --- a/src/FluentValidation/Internal/MemberNameValidatorSelector.cs +++ b/src/FluentValidation/Internal/MemberNameValidatorSelector.cs @@ -73,13 +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."); } - var propertyName = ValidatorOptions.Global.PropertyNameResolver(typeof(T), expression.GetMember(), expression); return propertyName; } }