2024-08-17 16:38:40 +02:00
using FluentValidation ;
using FluentValidation.Results ;
using Microsoft.Extensions.Options ;
2025-06-12 18:22:37 +02:00
namespace Vegasco.Server.Api.Common ;
2024-08-17 16:38:40 +02:00
public static class ValidatorExtensions
{
/// <summary>
/// Asynchronously validates an instance of <typeparamref name="T"/> against all <see cref="IValidator{T}"/> instances in <paramref name="validators"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="validators"></param>
/// <param name="instance"></param>
/// <returns>The failed validation results.</returns>
2024-08-17 16:38:40 +02:00
public static async Task < List < ValidationResult > > ValidateAllAsync < T > ( this IEnumerable < IValidator < T > > validators , T instance , CancellationToken cancellationToken = default )
2024-08-17 16:38:40 +02:00
{
2025-06-12 17:43:22 +02:00
List < Task < ValidationResult > > validationTasks = validators
2024-08-17 16:38:40 +02:00
. Select ( validator = > validator . ValidateAsync ( instance , cancellationToken ) )
2024-08-17 16:38:40 +02:00
. ToList ( ) ;
await Task . WhenAll ( validationTasks ) ;
List < ValidationResult > failedValidations = validationTasks
. Select ( x = > x . Result )
. Where ( x = > ! x . IsValid )
. ToList ( ) ;
return failedValidations ;
}
public static Dictionary < string , string [ ] > ToCombinedDictionary ( this IEnumerable < ValidationResult > validationResults )
{
// Use a hash set to avoid duplicate error messages.
Dictionary < string , HashSet < string > > combinedErrors = [ ] ;
2025-06-12 17:43:22 +02:00
foreach ( ValidationFailure ? error in validationResults . SelectMany ( x = > x . Errors ) )
2024-08-17 16:38:40 +02:00
{
if ( ! combinedErrors . TryGetValue ( error . PropertyName , out HashSet < string > ? value ) )
{
2025-06-12 18:22:37 +02:00
value = [ error . ErrorMessage ] ;
2024-08-17 16:38:40 +02:00
combinedErrors [ error . PropertyName ] = value ;
continue ;
}
value . Add ( error . ErrorMessage ) ;
}
return combinedErrors . ToDictionary ( x = > x . Key , x = > x . Value . ToArray ( ) ) ;
}
public static OptionsBuilder < T > ValidateFluently < T > ( this OptionsBuilder < T > builder )
where T : class
{
builder . Services . AddTransient < IValidateOptions < T > > ( serviceProvider = >
{
2025-06-12 17:43:22 +02:00
IEnumerable < IValidator < T > > validators = serviceProvider . GetServices < IValidator < T > > ( ) ? ? [ ] ;
2024-08-17 16:38:40 +02:00
return new FluentValidationOptions < T > ( builder . Name , validators ) ;
} ) ;
return builder ;
}
}