From 5510ae05ce80893177f17d24981523bdeb4bd0b3 Mon Sep 17 00:00:00 2001 From: "sbauman@makorsolutions.com" Date: Tue, 25 Apr 2023 13:47:38 -0500 Subject: [PATCH 1/4] validate compared to --- samples/BlazorServer/Pages/Index.razor | 16 ++++++- samples/BlazorWebAssembly/Pages/Index.razor | 12 +++++ samples/Shared/SharedModels/Person.cs | 5 +++ .../EditContextFluentValidationExtensions.cs | 45 ++++++++++++++++--- 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/samples/BlazorServer/Pages/Index.razor b/samples/BlazorServer/Pages/Index.razor index f227a9f..25d1611 100644 --- a/samples/BlazorServer/Pages/Index.razor +++ b/samples/BlazorServer/Pages/Index.razor @@ -63,6 +63,18 @@

+

+ + + +

+ +

+ + + +

+ @@ -73,9 +85,9 @@ private readonly Person _person = new(); private FluentValidationValidator? _fluentValidationValidator; - private void SubmitValidForm() + private void SubmitValidForm() => Console.WriteLine("Form Submitted Successfully!"); - private void PartialValidate() + private void PartialValidate() => Console.WriteLine($"Partial validation result : {_fluentValidationValidator?.Validate(options => options.IncludeRuleSets("Names"))}"); } \ No newline at end of file diff --git a/samples/BlazorWebAssembly/Pages/Index.razor b/samples/BlazorWebAssembly/Pages/Index.razor index 400e083..8e8452a 100644 --- a/samples/BlazorWebAssembly/Pages/Index.razor +++ b/samples/BlazorWebAssembly/Pages/Index.razor @@ -63,6 +63,18 @@

+

+ + + +

+ +

+ + + +

+ diff --git a/samples/Shared/SharedModels/Person.cs b/samples/Shared/SharedModels/Person.cs index 412ae40..7de8f5c 100644 --- a/samples/Shared/SharedModels/Person.cs +++ b/samples/Shared/SharedModels/Person.cs @@ -9,6 +9,8 @@ public class Person public int? Age { get; set; } public string? EmailAddress { get; set; } public Address Address { get; set; } = new(); + public int StartLuckyNumberRange { get; set; } + public int EndLuckyNumberRange { get; set; } } public class PersonValidator : AbstractValidator @@ -36,6 +38,9 @@ public PersonValidator() .EmailAddress().WithMessage("You must provide a valid email address") .MustAsync(async (email, _) => await IsUniqueAsync(email)).WithMessage("Email address must be unique"); + RuleFor(p => p.StartLuckyNumberRange).LessThan(p => p.EndLuckyNumberRange).WithMessage("Start lucky number must be less than end lucky number"); + RuleFor(p => p.EndLuckyNumberRange).GreaterThan(p => p.StartLuckyNumberRange).WithMessage("End lucky number must be greater than start lucky number"); + RuleFor(p => p.Address).SetValidator(new AddressValidator()); } diff --git a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs index c06c9f4..ea90431 100644 --- a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs +++ b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs @@ -1,5 +1,6 @@ using FluentValidation; using FluentValidation.Internal; +using FluentValidation.Validators; using Microsoft.AspNetCore.Components.Forms; using Microsoft.Extensions.DependencyInjection; using static FluentValidation.AssemblyScanner; @@ -76,15 +77,45 @@ private static async Task ValidateField(EditContext editContext, { var properties = new[] { fieldIdentifier.FieldName }; var context = new ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties)); - + validator ??= GetValidatorForModel(serviceProvider, fieldIdentifier.Model, disableAssemblyScanning); if (validator is not null) { var validationResults = await validator.ValidateAsync(context); + var validationRules = validator as IEnumerable; + var members = new List(); - messages.Clear(fieldIdentifier); - messages.Add(fieldIdentifier, validationResults.Errors.Select(error => error.ErrorMessage)); + if (validationRules != null) + { + foreach (var rule in validationRules) + { + var maybeComparison = rule.Components.FirstOrDefault()?.Validator; + + if (maybeComparison != null && maybeComparison is IComparisonValidator comparisonValidator) + { + var compareTo = comparisonValidator.MemberToCompare.Name; + if (!members.Contains(compareTo) && rule.PropertyName == fieldIdentifier.FieldName) + { + members.Add(compareTo); + var newProperties = properties.ToList(); + newProperties.Add(compareTo); + properties = newProperties.ToArray(); + context = new ValidationContext(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties)); + validationResults = await validator.ValidateAsync(context); + } + } + else + members.Add(fieldIdentifier.FieldName); + } + } + + foreach (var member in members) + { + var field = new FieldIdentifier(fieldIdentifier.Model, member); + messages.Clear(field); + messages.Add(field, validationResults.Errors.Where(x => x.PropertyName == field.FieldName).Select(error => error.ErrorMessage)); + } editContext.NotifyValidationStateChanged(); } @@ -148,7 +179,7 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in var obj = editContext.Model; var nextTokenEnd = propertyPath.IndexOfAny(Separators); - + // Optimize for a scenario when parsing isn't needed. if (nextTokenEnd < 0) { @@ -175,8 +206,8 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in // we've got an Item property var indexerType = prop.GetIndexParameters()[0].ParameterType; var indexerValue = Convert.ChangeType(nextToken.ToString(), indexerType); - - newObj = prop.GetValue(obj, new [] { indexerValue }); + + newObj = prop.GetValue(obj, new[] { indexerValue }); } else { @@ -211,7 +242,7 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in } obj = newObj; - + nextTokenEnd = propertyPathAsSpan.IndexOfAny(Separators); if (nextTokenEnd < 0) { From 98bf24b4498208b6d6fa10c3634c7e0a50133c5d Mon Sep 17 00:00:00 2001 From: "sbauman@makorsolutions.com" Date: Tue, 9 May 2023 09:39:26 -0500 Subject: [PATCH 2/4] spaces --- samples/BlazorServer/Pages/Index.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/BlazorServer/Pages/Index.razor b/samples/BlazorServer/Pages/Index.razor index 25d1611..b96e7d7 100644 --- a/samples/BlazorServer/Pages/Index.razor +++ b/samples/BlazorServer/Pages/Index.razor @@ -85,9 +85,9 @@ private readonly Person _person = new(); private FluentValidationValidator? _fluentValidationValidator; - private void SubmitValidForm() + private void SubmitValidForm() => Console.WriteLine("Form Submitted Successfully!"); - private void PartialValidate() + private void PartialValidate() => Console.WriteLine($"Partial validation result : {_fluentValidationValidator?.Validate(options => options.IncludeRuleSets("Names"))}"); } \ No newline at end of file From ad594d247c4f58436d5ac39d32f7d5a2f0d6237c Mon Sep 17 00:00:00 2001 From: "sbauman@makorsolutions.com" Date: Tue, 9 May 2023 09:42:58 -0500 Subject: [PATCH 3/4] more spaces --- .../EditContextFluentValidationExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs index ea90431..980ca29 100644 --- a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs +++ b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs @@ -207,7 +207,7 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in var indexerType = prop.GetIndexParameters()[0].ParameterType; var indexerValue = Convert.ChangeType(nextToken.ToString(), indexerType); - newObj = prop.GetValue(obj, new[] { indexerValue }); + newObj = prop.GetValue(obj, new [] { indexerValue }); } else { From 655153010d56c6ff4d72a0eed7f46a8518446c4d Mon Sep 17 00:00:00 2001 From: "sbauman@makorsolutions.com" Date: Tue, 9 May 2023 16:07:32 -0500 Subject: [PATCH 4/4] spaces --- .../EditContextFluentValidationExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs index 980ca29..206e769 100644 --- a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs +++ b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs @@ -179,7 +179,7 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in var obj = editContext.Model; var nextTokenEnd = propertyPath.IndexOfAny(Separators); - + // Optimize for a scenario when parsing isn't needed. if (nextTokenEnd < 0) { @@ -206,7 +206,7 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in // we've got an Item property var indexerType = prop.GetIndexParameters()[0].ParameterType; var indexerValue = Convert.ChangeType(nextToken.ToString(), indexerType); - + newObj = prop.GetValue(obj, new [] { indexerValue }); } else @@ -242,7 +242,7 @@ private static FieldIdentifier ToFieldIdentifier(in EditContext editContext, in } obj = newObj; - + nextTokenEnd = propertyPathAsSpan.IndexOfAny(Separators); if (nextTokenEnd < 0) {