Skip to content

Commit

Permalink
enable interception of edit context model type when attempting to ret…
Browse files Browse the repository at this point in the history
…rieve validator instances
  • Loading branch information
RyanMarcotte committed Jun 18, 2021
1 parent 45485a7 commit 032ba8d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,40 @@ public static class EditContextFluentValidationExtensions
private static readonly List<AssemblyScanResult> AssemblyScanResults = new List<AssemblyScanResult>();

public static EditContext AddFluentValidation(this EditContext editContext, IServiceProvider serviceProvider, bool disableAssemblyScanning, IValidator validator, FluentValidationValidator fluentValidationValidator)
=> editContext.AddFluentValidation(serviceProvider, disableAssemblyScanning, validator, fluentValidationValidator, FluentValidationValidator.ModelTypePassthrough);

public static EditContext AddFluentValidation(this EditContext editContext, IServiceProvider serviceProvider, bool disableAssemblyScanning, IValidator validator, FluentValidationValidator fluentValidationValidator, MakeTypeUsingEditContextModelDelegate modelTypeFunc)
{
if (editContext == null)
{
throw new ArgumentNullException(nameof(editContext));
}

if (modelTypeFunc == null)
{
throw new ArgumentNullException(nameof(modelTypeFunc));
}

var messages = new ValidationMessageStore(editContext);

editContext.OnValidationRequested +=
(sender, eventArgs) => ValidateModel((EditContext)sender, messages, serviceProvider, disableAssemblyScanning, fluentValidationValidator, validator);
(sender, eventArgs) => ValidateModel((EditContext)sender, messages, serviceProvider, disableAssemblyScanning, fluentValidationValidator, validator, modelTypeFunc);

editContext.OnFieldChanged +=
(sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier, serviceProvider, disableAssemblyScanning, validator);
(sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier, serviceProvider, disableAssemblyScanning, validator, modelTypeFunc);

return editContext;
}

private static async void ValidateModel(EditContext editContext,
ValidationMessageStore messages,
IServiceProvider serviceProvider,
bool disableAssemblyScanning,
FluentValidationValidator fluentValidationValidator,
IValidator validator = null)
ValidationMessageStore messages,
IServiceProvider serviceProvider,
bool disableAssemblyScanning,
FluentValidationValidator fluentValidationValidator,
IValidator validator,
MakeTypeUsingEditContextModelDelegate modelTypeFunc)
{
validator ??= GetValidatorForModel(serviceProvider, editContext.Model, disableAssemblyScanning);
validator ??= GetValidatorForModel(serviceProvider, editContext.Model, disableAssemblyScanning, modelTypeFunc);

if (validator is object)
{
Expand All @@ -61,16 +69,17 @@ private static async void ValidateModel(EditContext editContext,
}

private static async void ValidateField(EditContext editContext,
ValidationMessageStore messages,
FieldIdentifier fieldIdentifier,
IServiceProvider serviceProvider,
bool disableAssemblyScanning,
IValidator validator = null)
ValidationMessageStore messages,
FieldIdentifier fieldIdentifier,
IServiceProvider serviceProvider,
bool disableAssemblyScanning,
IValidator validator,
MakeTypeUsingEditContextModelDelegate modelTypeFunc)
{
var properties = new[] { fieldIdentifier.FieldName };
var context = new ValidationContext<object>(fieldIdentifier.Model, new PropertyChain(), new MemberNameValidatorSelector(properties));

validator ??= GetValidatorForModel(serviceProvider, fieldIdentifier.Model, disableAssemblyScanning);
validator ??= GetValidatorForModel(serviceProvider, fieldIdentifier.Model, disableAssemblyScanning, modelTypeFunc);

if (validator is object)
{
Expand All @@ -83,9 +92,10 @@ private static async void ValidateField(EditContext editContext,
}
}

private static IValidator GetValidatorForModel(IServiceProvider serviceProvider, object model, bool disableAssemblyScanning)
private static IValidator GetValidatorForModel(IServiceProvider serviceProvider, object model, bool disableAssemblyScanning, MakeTypeUsingEditContextModelDelegate modelTypeFunc)
{
var validatorType = typeof(IValidator<>).MakeGenericType(model.GetType());
var modelType = modelTypeFunc.Invoke(model.GetType());
var validatorType = typeof(IValidator<>).MakeGenericType(modelType);
if (serviceProvider != null)
{
try
Expand Down Expand Up @@ -119,7 +129,7 @@ private static IValidator GetValidatorForModel(IServiceProvider serviceProvider,
}


var interfaceValidatorType = typeof(IValidator<>).MakeGenericType(model.GetType());
var interfaceValidatorType = typeof(IValidator<>).MakeGenericType(modelType);

Type modelValidatorType = AssemblyScanResults.FirstOrDefault(i => interfaceValidatorType.IsAssignableFrom(i.InterfaceType))?.ValidatorType;

Expand Down
5 changes: 4 additions & 1 deletion src/Blazored.FluentValidation/FluentValidationsValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ namespace Blazored.FluentValidation
{
public class FluentValidationValidator : ComponentBase
{
internal static readonly MakeTypeUsingEditContextModelDelegate ModelTypePassthrough = model => model.GetType();

[Inject] private IServiceProvider ServiceProvider { get; set; }

[CascadingParameter] private EditContext CurrentEditContext { get; set; }

[Parameter] public IValidator Validator { get; set; }
[Parameter] public bool DisableAssemblyScanning { get; set; }
[Parameter] public MakeTypeUsingEditContextModelDelegate ModelTypeFunc { get; set; }

internal Action<ValidationStrategy<object>> Options;

Expand All @@ -40,7 +43,7 @@ protected override void OnInitialized()
$"inside an {nameof(EditForm)}.");
}

CurrentEditContext.AddFluentValidation(ServiceProvider, DisableAssemblyScanning, Validator, this);
CurrentEditContext.AddFluentValidation(ServiceProvider, DisableAssemblyScanning, Validator, this, ModelTypeFunc ?? ModelTypePassthrough);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Blazored.FluentValidation
{
public delegate Type MakeTypeUsingEditContextModelDelegate(object model);
}

0 comments on commit 032ba8d

Please sign in to comment.