using System.Reflection; using FluentValidation; using Microsoft.Extensions.DependencyInjection; using PnvPanel.Application.Common.Behaviors; using PnvPanel.Application.Common.Messaging; namespace PnvPanel.Application; /// /// Точка регистрации сервисов слоя Application: собственный CQRS-диспетчер (ISender), /// хендлеры/валидаторы (авто-сканирование сборки) и pipeline behaviors — в порядке выполнения. /// public static class DependencyInjection { public static IServiceCollection AddApplication(this IServiceCollection services) { var assembly = typeof(DependencyInjection).Assembly; services.AddScoped(); RegisterClosedGeneric(services, assembly, typeof(ICommandHandler<,>)); RegisterClosedGeneric(services, assembly, typeof(IQueryHandler<,>)); RegisterClosedGeneric(services, assembly, typeof(IValidator<>)); // Порядок важен: Logging (снаружи) -> Validation -> RequireActivation -> UnitOfWork (ближе к хендлеру). services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequireActivationBehavior<,>)); services.AddScoped(typeof(IPipelineBehavior<,>), typeof(UnitOfWorkBehavior<,>)); return services; } private static void RegisterClosedGeneric(IServiceCollection services, Assembly assembly, Type openInterface) { var implementations = assembly.GetTypes() .Where(t => t is { IsClass: true, IsAbstract: false }) .SelectMany(t => t.GetInterfaces() .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == openInterface) .Select(i => (Service: i, Implementation: t))); foreach (var (service, implementation) in implementations) services.AddScoped(service, implementation); } }