|
@@ -2,14 +2,44 @@
|
|
|
|
|
|
|
|
using FluentValidation;
|
|
using FluentValidation;
|
|
|
using FluentValidation.Internal;
|
|
using FluentValidation.Internal;
|
|
|
|
|
+using FluentValidation.Results;
|
|
|
using FluentValidation.Validators;
|
|
using FluentValidation.Validators;
|
|
|
|
|
|
|
|
using Microsoft.AspNetCore.Components.Forms;
|
|
using Microsoft.AspNetCore.Components.Forms;
|
|
|
|
|
|
|
|
namespace BlazorEditForms;
|
|
namespace BlazorEditForms;
|
|
|
|
|
|
|
|
|
|
+public static class ValidationFailureExtensions
|
|
|
|
|
+{
|
|
|
|
|
+ private const string FieldIdentifierKey = $"{nameof(FieldIdentifier)}_Key";
|
|
|
|
|
+
|
|
|
|
|
+ public static FieldIdentifier? GetFieldIdentifier(this ValidationFailure failure)
|
|
|
|
|
+ {
|
|
|
|
|
+ failure.FormattedMessagePlaceholderValues.TryGetValue(FieldIdentifierKey, out var fieldIdentifier);
|
|
|
|
|
+ return (FieldIdentifier?)fieldIdentifier;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static void SetFieldIdentifier(this ValidationFailure failure, FieldIdentifier fieldIdentifier)
|
|
|
|
|
+ {
|
|
|
|
|
+ failure.FormattedMessagePlaceholderValues[FieldIdentifierKey] = fieldIdentifier;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
public class CustomFluentValidationManager : IDisposable
|
|
public class CustomFluentValidationManager : IDisposable
|
|
|
{
|
|
{
|
|
|
|
|
+ static CustomFluentValidationManager()
|
|
|
|
|
+ {
|
|
|
|
|
+ ValidatorOptions.Global.OnFailureCreated = (failure, context, value, rule, component) =>
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!string.IsNullOrEmpty(rule.PropertyName))
|
|
|
|
|
+ {
|
|
|
|
|
+ failure.SetFieldIdentifier(new FieldIdentifier(context.InstanceToValidate, rule.PropertyName));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return failure;
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private readonly EventHandler<ValidationRequestedEventArgs> _validationRequestedHandler;
|
|
private readonly EventHandler<ValidationRequestedEventArgs> _validationRequestedHandler;
|
|
|
private readonly EventHandler<FieldChangedEventArgs> _fieldChangedHandler;
|
|
private readonly EventHandler<FieldChangedEventArgs> _fieldChangedHandler;
|
|
|
|
|
|
|
@@ -32,25 +62,12 @@ public class CustomFluentValidationManager : IDisposable
|
|
|
// separate API to manage the validation messages that can (with public methods) only be _extracted from_ the
|
|
// separate API to manage the validation messages that can (with public methods) only be _extracted from_ the
|
|
|
// edit context.
|
|
// edit context.
|
|
|
_validationMessageStore = new ValidationMessageStore(_editContext);
|
|
_validationMessageStore = new ValidationMessageStore(_editContext);
|
|
|
-
|
|
|
|
|
- // TODO: how to make this multi-threaded ?
|
|
|
|
|
- ValidatorOptions.Global.OnFailureCreated = (failure, context, value, rule, component) =>
|
|
|
|
|
- {
|
|
|
|
|
- if (!string.IsNullOrEmpty(rule.PropertyName))
|
|
|
|
|
- {
|
|
|
|
|
- failure.FormattedMessagePlaceholderValues["MINE"] =
|
|
|
|
|
- new FieldIdentifier(context.InstanceToValidate, rule.PropertyName);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return failure;
|
|
|
|
|
- };
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private async Task ValidateModel()
|
|
private async Task ValidateModel()
|
|
|
{
|
|
{
|
|
|
var validationContext = ValidationContext<object>.CreateWithOptions(_editContext.Model, strategy =>
|
|
var validationContext = ValidationContext<object>.CreateWithOptions(_editContext.Model, strategy =>
|
|
|
{
|
|
{
|
|
|
- //strategy.UseCustomSelector(new MySelector());
|
|
|
|
|
strategy.IncludeRulesNotInRuleSet();
|
|
strategy.IncludeRulesNotInRuleSet();
|
|
|
});
|
|
});
|
|
|
var validationResult = await _validator.ValidateAsync(validationContext);
|
|
var validationResult = await _validator.ValidateAsync(validationContext);
|
|
@@ -58,10 +75,10 @@ public class CustomFluentValidationManager : IDisposable
|
|
|
_validationMessageStore.Clear();
|
|
_validationMessageStore.Clear();
|
|
|
foreach (var failure in validationResult.Errors)
|
|
foreach (var failure in validationResult.Errors)
|
|
|
{
|
|
{
|
|
|
- if (failure.FormattedMessagePlaceholderValues.TryGetValue("MINE", out var mine))
|
|
|
|
|
|
|
+ var fieldIdentifier = failure.GetFieldIdentifier();
|
|
|
|
|
+ if (fieldIdentifier.HasValue)
|
|
|
{
|
|
{
|
|
|
- var fieldIdentifier = (FieldIdentifier)mine;
|
|
|
|
|
- _validationMessageStore.Add(fieldIdentifier, failure.ErrorMessage);
|
|
|
|
|
|
|
+ _validationMessageStore.Add(fieldIdentifier.Value, failure.ErrorMessage);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -73,7 +90,6 @@ public class CustomFluentValidationManager : IDisposable
|
|
|
var validationContext = ValidationContext<object>.CreateWithOptions(_editContext.Model, strategy =>
|
|
var validationContext = ValidationContext<object>.CreateWithOptions(_editContext.Model, strategy =>
|
|
|
{
|
|
{
|
|
|
strategy.UseCustomSelector(new FieldIdentifierSelector(fieldIdentifier));
|
|
strategy.UseCustomSelector(new FieldIdentifierSelector(fieldIdentifier));
|
|
|
- //strategy.IncludeRulesNotInRuleSet();
|
|
|
|
|
});
|
|
});
|
|
|
var validationResult = await _validator.ValidateAsync(validationContext);
|
|
var validationResult = await _validator.ValidateAsync(validationContext);
|
|
|
|
|
|
|
@@ -81,12 +97,10 @@ public class CustomFluentValidationManager : IDisposable
|
|
|
|
|
|
|
|
foreach (var failure in validationResult.Errors)
|
|
foreach (var failure in validationResult.Errors)
|
|
|
{
|
|
{
|
|
|
- if (failure.FormattedMessagePlaceholderValues.TryGetValue("MINE", out var mine))
|
|
|
|
|
|
|
+ var failureIdentifier = failure.GetFieldIdentifier();
|
|
|
|
|
+ if (fieldIdentifier.Equals(failureIdentifier))
|
|
|
{
|
|
{
|
|
|
- if (fieldIdentifier.Equals(mine))
|
|
|
|
|
- {
|
|
|
|
|
- _validationMessageStore.Add(fieldIdentifier, failure.ErrorMessage);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ _validationMessageStore.Add(fieldIdentifier, failure.ErrorMessage);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|