diff --git a/samples/BlazorServer/Pages/Index.razor b/samples/BlazorServer/Pages/Index.razor index f227a9f..b96e7d7 100644 --- a/samples/BlazorServer/Pages/Index.razor +++ b/samples/BlazorServer/Pages/Index.razor @@ -63,6 +63,18 @@

+

+ + + +

+ +

+ + + +

+ 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..206e769 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(); }