Created
April 13, 2020 21:21
-
-
Save ahancock1/b89cacc6230a9329ef281bc8e8a70bc9 to your computer and use it in GitHub Desktop.
Simple Blazor Fluent Validation Validator Component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class FluentValidator : ComponentBase | |
{ | |
private readonly IDictionary<Type, IValidator> _validators = | |
new Dictionary<Type, IValidator>(); | |
[CascadingParameter] | |
public EditContext EditContext { get; set; } | |
[Inject] | |
private IServiceProvider ServiceProvider { get; set; } | |
protected override void OnInitialized() | |
{ | |
if (EditContext == null) | |
{ | |
throw new InvalidOperationException( | |
$"{nameof(FluentValidator)} requires a cascading parameter."); | |
} | |
GetOrAddValidator(EditContext.Model.GetType()); | |
var messages = new ValidationMessageStore(EditContext); | |
EditContext.OnValidationRequested += | |
(s, _) => ValidateModel((EditContext) s, messages); | |
EditContext.OnFieldChanged += | |
(_, e) => ValidateField(EditContext, messages, e.FieldIdentifier); | |
} | |
private IValidator GetOrAddValidator(Type type) | |
{ | |
if (!_validators.ContainsKey(type)) | |
{ | |
_validators[type] = CreateValidator(type); | |
} | |
return _validators[type]; | |
} | |
private IValidator CreateValidator(Type type) | |
{ | |
return (IValidator) ServiceProvider | |
.GetService(typeof(IValidator<>).MakeGenericType(type)); | |
} | |
public FieldIdentifier FindFieldIdentifier(object model, string property) | |
{ | |
var split = property.Split(new[] {"[", "].", "."}, StringSplitOptions.None); | |
var walker = model; | |
foreach (var item in split.Take(split.Length - 1)) | |
{ | |
if (walker == null) | |
{ | |
break; | |
} | |
switch (item) | |
{ | |
case { } when int.TryParse(item, out var index): | |
{ | |
if (walker is IList array) | |
{ | |
walker = array[index]; | |
} | |
break; | |
} | |
default: | |
{ | |
walker = walker.GetType().GetProperty(item)?.GetValue(walker); | |
break; | |
} | |
} | |
} | |
return new FieldIdentifier(walker, split.Last()); | |
} | |
private void ValidateModel(EditContext context, ValidationMessageStore messages) | |
{ | |
var validator = GetOrAddValidator(context.Model.GetType()); | |
var result = validator.Validate(context.Model); | |
messages.Clear(); | |
foreach (var error in result.Errors) | |
{ | |
var identifier = FindFieldIdentifier(context.Model, error.PropertyName); | |
messages.Add(identifier, error.ErrorMessage); | |
} | |
context.NotifyValidationStateChanged(); | |
} | |
private void ValidateField(EditContext context, ValidationMessageStore messages, | |
in FieldIdentifier identifier) | |
{ | |
var validator = GetOrAddValidator(identifier.Model.GetType()); | |
if (validator == null) | |
{ | |
return; | |
} | |
var result = validator.Validate( | |
new ValidationContext( | |
identifier.Model, | |
new PropertyChain(), | |
new MemberNameValidatorSelector( | |
new[] | |
{ | |
identifier.FieldName | |
}))); | |
messages.Clear(identifier); | |
foreach (var error in result.Errors) | |
{ | |
messages.Add(identifier, error.ErrorMessage); | |
} | |
context.NotifyValidationStateChanged(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment