feat: add support for validator resolution from dependency injection
This commit is contained in:
parent
21ca8a3757
commit
22142882b5
19 changed files with 806 additions and 1 deletions
69
src/request.validation/DispatchingValidator.cs
Normal file
69
src/request.validation/DispatchingValidator.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) The Geekeey Authors
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
[assembly: MetadataUpdateHandler(typeof(Geekeey.Request.Validation.DispatchingValidator))]
|
||||
|
||||
namespace Geekeey.Request.Validation;
|
||||
|
||||
internal sealed class DispatchingValidator : IValidator
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, ValidatorInvoker> ValidatorsHandlers = new();
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public DispatchingValidator(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Validation Validate(ValidationContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
|
||||
if (context.Instance is null)
|
||||
{
|
||||
return new Validation([]);
|
||||
}
|
||||
|
||||
var handler = ValidatorsHandlers.GetOrAdd(context.Instance.GetType(), static key =>
|
||||
{
|
||||
var type = typeof(ValidatorInvoker<>).MakeGenericType(key);
|
||||
return (ValidatorInvoker)Activator.CreateInstance(type)!;
|
||||
});
|
||||
|
||||
return handler.Validate(context, _serviceProvider);
|
||||
}
|
||||
|
||||
private abstract class ValidatorInvoker
|
||||
{
|
||||
public abstract Validation Validate(ValidationContext context, IServiceProvider serviceProvider);
|
||||
}
|
||||
|
||||
private sealed class ValidatorInvoker<T> : ValidatorInvoker
|
||||
{
|
||||
public override Validation Validate(ValidationContext context, IServiceProvider serviceProvider)
|
||||
{
|
||||
var options = serviceProvider.GetRequiredService<IOptions<ValidationOptions>>().Value;
|
||||
|
||||
var validators = options.GetValidators<T>(serviceProvider);
|
||||
|
||||
var problems = new List<Problem>();
|
||||
|
||||
foreach (var validator in validators)
|
||||
{
|
||||
if (validator.Validate(context) is { IsValid: false, Problems: { } result })
|
||||
{
|
||||
problems.AddRange(result);
|
||||
}
|
||||
}
|
||||
|
||||
return new Validation(problems);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue