145 lines
6.9 KiB
C#
145 lines
6.9 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using FluentValidation;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Svrnty.CQRS.Abstractions;
|
|
|
|
namespace Svrnty.CQRS.FluentValidation;
|
|
|
|
public static class ServiceCollectionExtensions
|
|
{
|
|
private static IServiceCollection AddFluentValidator<T, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TValidator>(this IServiceCollection services)
|
|
where TValidator : class, IValidator<T>
|
|
{
|
|
services.AddTransient<IValidator<T>, TValidator>();
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddCommand<TCommand, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCommandHandler, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TValidator>(this IServiceCollection services)
|
|
where TCommand : class
|
|
where TCommandHandler : class, ICommandHandler<TCommand>
|
|
where TValidator : class, IValidator<TCommand>
|
|
{
|
|
return services.AddCommand<TCommand, TCommandHandler>()
|
|
.AddFluentValidator<TCommand, TValidator>();
|
|
}
|
|
|
|
public static IServiceCollection AddCommand<TCommand, TCommandResult, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCommandHandler, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TValidator>(this IServiceCollection services)
|
|
where TCommand : class
|
|
where TCommandHandler : class, ICommandHandler<TCommand, TCommandResult>
|
|
where TValidator : class, IValidator<TCommand>
|
|
{
|
|
return services.AddCommand<TCommand, TCommandResult, TCommandHandler>()
|
|
.AddFluentValidator<TCommand, TValidator>();
|
|
}
|
|
|
|
public static IServiceCollection AddQuery<TQuery, TQueryResult, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TQueryHandler, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TValidator>(this IServiceCollection services)
|
|
where TQuery : class
|
|
where TQueryHandler : class, IQueryHandler<TQuery, TQueryResult>
|
|
where TValidator : class, IValidator<TQuery>
|
|
{
|
|
services.AddQuery<TQuery, TQueryResult, TQueryHandler>()
|
|
.AddFluentValidator<TQuery, TValidator>();
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scans the specified assembly and registers all FluentValidation validators found.
|
|
/// Supports multiple validators per type (e.g., for composite validation scenarios).
|
|
/// </summary>
|
|
/// <param name="services">The service collection</param>
|
|
/// <param name="assembly">The assembly to scan for validators</param>
|
|
/// <param name="filter">Optional filter to include/exclude specific validator types</param>
|
|
/// <param name="lifetime">Service lifetime for validators (default: Transient)</param>
|
|
/// <returns>The service collection for chaining</returns>
|
|
public static IServiceCollection AddValidatorsFromAssembly(
|
|
this IServiceCollection services,
|
|
Assembly assembly,
|
|
Func<Type, bool>? filter = null,
|
|
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
|
{
|
|
return AddValidatorsFromAssembly(services, assembly, filter, null, lifetime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scans the specified assembly and registers FluentValidation validators for command types only.
|
|
/// Filters validators to only include those validating types ending with "Command" or registered as command handlers.
|
|
/// </summary>
|
|
/// <param name="services">The service collection</param>
|
|
/// <param name="assembly">The assembly to scan for validators</param>
|
|
/// <param name="filter">Optional additional filter to include/exclude specific validator types</param>
|
|
/// <param name="lifetime">Service lifetime for validators (default: Transient)</param>
|
|
/// <returns>The service collection for chaining</returns>
|
|
public static IServiceCollection AddCommandValidatorsFromAssembly(
|
|
this IServiceCollection services,
|
|
Assembly assembly,
|
|
Func<Type, bool>? filter = null,
|
|
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
|
{
|
|
return AddValidatorsFromAssembly(
|
|
services,
|
|
assembly,
|
|
filter,
|
|
validatedType => validatedType.Name.EndsWith("Command", StringComparison.Ordinal),
|
|
lifetime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scans the specified assembly and registers FluentValidation validators for query types only.
|
|
/// Filters validators to only include those validating types ending with "Query" or registered as query handlers.
|
|
/// </summary>
|
|
/// <param name="services">The service collection</param>
|
|
/// <param name="assembly">The assembly to scan for validators</param>
|
|
/// <param name="filter">Optional additional filter to include/exclude specific validator types</param>
|
|
/// <param name="lifetime">Service lifetime for validators (default: Transient)</param>
|
|
/// <returns>The service collection for chaining</returns>
|
|
public static IServiceCollection AddQueryValidatorsFromAssembly(
|
|
this IServiceCollection services,
|
|
Assembly assembly,
|
|
Func<Type, bool>? filter = null,
|
|
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
|
{
|
|
return AddValidatorsFromAssembly(
|
|
services,
|
|
assembly,
|
|
filter,
|
|
validatedType => validatedType.Name.EndsWith("Query", StringComparison.Ordinal),
|
|
lifetime);
|
|
}
|
|
|
|
private static IServiceCollection AddValidatorsFromAssembly(
|
|
IServiceCollection services,
|
|
Assembly assembly,
|
|
Func<Type, bool>? validatorTypeFilter,
|
|
Func<Type, bool>? validatedTypeFilter,
|
|
ServiceLifetime lifetime)
|
|
{
|
|
var validatorInterfaces = assembly.GetTypes()
|
|
.Where(type => type.IsClass && !type.IsAbstract && !type.IsGenericTypeDefinition)
|
|
.Where(type => validatorTypeFilter == null || validatorTypeFilter(type))
|
|
.SelectMany(validatorType => validatorType.GetInterfaces()
|
|
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>))
|
|
.Select(interfaceType => new { ValidatorType = validatorType, InterfaceType = interfaceType }))
|
|
.ToList();
|
|
|
|
foreach (var registration in validatorInterfaces)
|
|
{
|
|
var validatedType = registration.InterfaceType.GetGenericArguments()[0];
|
|
|
|
// Apply validated type filter (for command/query separation)
|
|
if (validatedTypeFilter != null && !validatedTypeFilter(validatedType))
|
|
continue;
|
|
|
|
var validatorType = registration.ValidatorType;
|
|
|
|
// Register the validator
|
|
var serviceType = typeof(IValidator<>).MakeGenericType(validatedType);
|
|
services.Add(new ServiceDescriptor(serviceType, validatorType, lifetime));
|
|
}
|
|
|
|
return services;
|
|
}
|
|
} |