diff --git a/samples/BlazorServer/Pages/Index.razor b/samples/BlazorServer/Pages/Index.razor index f227a9f..4cc349e 100644 --- a/samples/BlazorServer/Pages/Index.razor +++ b/samples/BlazorServer/Pages/Index.razor @@ -68,6 +68,7 @@
+ @code { private readonly Person _person = new(); @@ -78,4 +79,14 @@ private void PartialValidate() => Console.WriteLine($"Partial validation result : {_fluentValidationValidator?.Validate(options => options.IncludeRuleSets("Names"))}"); + + private void AddValidationResult() + { + _fluentValidationValidator!.AddValidationResult(_person, new FluentValidation.Results.ValidationResult + { + Errors = new List { + new FluentValidation.Results.ValidationFailure { PropertyName = "EmailAddress", ErrorMessage = "This email address is taken already"} + } + }); + } } \ No newline at end of file diff --git a/samples/BlazorWebAssembly/Pages/Index.razor b/samples/BlazorWebAssembly/Pages/Index.razor index 400e083..367024f 100644 --- a/samples/BlazorWebAssembly/Pages/Index.razor +++ b/samples/BlazorWebAssembly/Pages/Index.razor @@ -68,6 +68,7 @@
+ @code { private readonly Person _person = new(); @@ -83,4 +84,14 @@ private void PartialValidate() => Console.WriteLine($"Partial validation result : {_fluentValidationValidator?.Validate(options => options.IncludeRuleSets("Names"))}"); + + private void AddValidationResult() + { + _fluentValidationValidator!.AddValidationResult(_person, new FluentValidation.Results.ValidationResult + { + Errors = new List { + new FluentValidation.Results.ValidationFailure { PropertyName = "EmailAddress", ErrorMessage = "This email address is taken already"} + } + }); + } } \ No newline at end of file diff --git a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs index c06c9f4..5477e08 100644 --- a/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs +++ b/src/Blazored.FluentValidation/EditContextFluentValidationExtensions.cs @@ -17,17 +17,14 @@ public static void AddFluentValidation(this EditContext editContext, IServicePro { ArgumentNullException.ThrowIfNull(editContext, nameof(editContext)); - var messages = new ValidationMessageStore(editContext); - editContext.OnValidationRequested += - async (sender, _) => await ValidateModel((EditContext)sender!, messages, serviceProvider, disableAssemblyScanning, fluentValidationValidator, validator); + async (sender, _) => await ValidateModel((EditContext)sender!, serviceProvider, disableAssemblyScanning, fluentValidationValidator, validator); editContext.OnFieldChanged += - async (_, eventArgs) => await ValidateField(editContext, messages, eventArgs.FieldIdentifier, serviceProvider, disableAssemblyScanning, validator); + async (_, eventArgs) => await ValidateField(editContext, fluentValidationValidator.Messages, eventArgs.FieldIdentifier, serviceProvider, disableAssemblyScanning, validator); } private static async Task ValidateModel(EditContext editContext, - ValidationMessageStore messages, IServiceProvider serviceProvider, bool disableAssemblyScanning, FluentValidationValidator fluentValidationValidator, @@ -56,11 +53,11 @@ private static async Task ValidateModel(EditContext editContext, editContext.Properties[PendingAsyncValidation] = asyncValidationTask; var validationResults = await asyncValidationTask; - messages.Clear(); + fluentValidationValidator.Messages.Clear(); foreach (var validationResult in validationResults.Errors) { var fieldIdentifier = ToFieldIdentifier(editContext, validationResult.PropertyName); - messages.Add(fieldIdentifier, validationResult.ErrorMessage); + fluentValidationValidator.Messages.Add(fieldIdentifier, validationResult.ErrorMessage); } editContext.NotifyValidationStateChanged(); diff --git a/src/Blazored.FluentValidation/FluentValidationsValidator.cs b/src/Blazored.FluentValidation/FluentValidationsValidator.cs index ae8e6f9..117d300 100644 --- a/src/Blazored.FluentValidation/FluentValidationsValidator.cs +++ b/src/Blazored.FluentValidation/FluentValidationsValidator.cs @@ -18,6 +18,8 @@ public class FluentValidationValidator : ComponentBase [Parameter] public Action>? Options { get; set; } internal Action>? ValidateOptions { get; set; } + internal ValidationMessageStore Messages { get; private set; } + public bool Validate(Action>? options = null) { if (CurrentEditContext is null) @@ -79,6 +81,30 @@ protected override void OnInitialized() $"inside an {nameof(EditForm)}."); } + Messages = new ValidationMessageStore(CurrentEditContext); CurrentEditContext.AddFluentValidation(ServiceProvider, DisableAssemblyScanning, Validator, this); } + + /// + /// Adds the validation errors contained in a FluentValidation ValidationResult object to the + /// current EditContext's validation messages. This allows for manual validation scenarios where + /// the ValidationResult may not be automatically integrated into Blazor's validation system. + /// Calling this method will update the validation state and the associated UI elements. + /// + /// The object instance that the validation applies to. This is used to + /// identify the form model within the EditContext. + /// The ValidationResult obtained from FluentValidation that contains + /// the details of any validation errors. + public void AddValidationResult(object model, ValidationResult validationResult) + { + if (CurrentEditContext != null && Messages != null) + { + foreach (ValidationFailure error in validationResult.Errors) + { + var fieldIdentifier = new FieldIdentifier(model, error.PropertyName); + Messages.Add(fieldIdentifier, error.ErrorMessage); + } + CurrentEditContext.NotifyValidationStateChanged(); + } + } } \ No newline at end of file