180 lines
7.5 KiB
C#
180 lines
7.5 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Svrnty.CQRS.Abstractions.Discovery;
|
|
|
|
namespace Svrnty.CQRS.Abstractions;
|
|
|
|
public static class ServiceCollectionExtensions
|
|
{
|
|
public static IServiceCollection AddQuery<TQuery, TQueryResult, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TQueryHandler>(this IServiceCollection services)
|
|
where TQuery : class
|
|
where TQueryHandler : class, IQueryHandler<TQuery, TQueryResult>
|
|
{
|
|
// add handler to DI.
|
|
services.AddTransient<IQueryHandler<TQuery, TQueryResult>, TQueryHandler>();
|
|
|
|
// add for discovery purposes.
|
|
var queryMeta = new QueryMeta(typeof(TQuery), typeof(IQueryHandler<TQuery, TQueryResult>), typeof(TQueryResult));
|
|
services.AddSingleton<IQueryMeta>(queryMeta);
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddCommand<TCommand, TCommandResult, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCommandHandler>(this IServiceCollection services)
|
|
where TCommand : class
|
|
where TCommandHandler : class, ICommandHandler<TCommand, TCommandResult>
|
|
{
|
|
// add handler to DI.
|
|
services.AddTransient<ICommandHandler<TCommand, TCommandResult>, TCommandHandler>();
|
|
|
|
// add for discovery purposes.
|
|
var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler<TCommand, TCommandResult>), typeof(TCommandResult));
|
|
services.AddSingleton<ICommandMeta>(commandMeta);
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddCommand<TCommand, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TCommandHandler>(this IServiceCollection services)
|
|
where TCommand : class
|
|
where TCommandHandler : class, ICommandHandler<TCommand>
|
|
{
|
|
// add handler to DI.
|
|
services.AddTransient<ICommandHandler<TCommand>, TCommandHandler>();
|
|
|
|
// add for discovery purposes.
|
|
var commandMeta = new CommandMeta(typeof(TCommand), typeof(ICommandHandler<TCommand>));
|
|
services.AddSingleton<ICommandMeta>(commandMeta);
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scans the specified assembly and registers all command handlers found.
|
|
/// </summary>
|
|
/// <param name="services">The service collection</param>
|
|
/// <param name="assembly">The assembly to scan for command handlers</param>
|
|
/// <param name="filter">Optional filter to include/exclude specific handler types</param>
|
|
/// <param name="lifetime">Service lifetime for handlers (default: Transient)</param>
|
|
/// <returns>The service collection for chaining</returns>
|
|
public static IServiceCollection AddCommandsFromAssembly(
|
|
this IServiceCollection services,
|
|
Assembly assembly,
|
|
Func<Type, bool>? filter = null,
|
|
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
|
{
|
|
var commandHandlerInterfaces = assembly.GetTypes()
|
|
.Where(type => type.IsClass && !type.IsAbstract && !type.IsGenericTypeDefinition)
|
|
.Where(type => filter == null || filter(type))
|
|
.SelectMany(handlerType => handlerType.GetInterfaces()
|
|
.Where(i => i.IsGenericType &&
|
|
(i.GetGenericTypeDefinition() == typeof(ICommandHandler<>) ||
|
|
i.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)))
|
|
.Select(interfaceType => new { HandlerType = handlerType, InterfaceType = interfaceType }))
|
|
.ToList();
|
|
|
|
foreach (var registration in commandHandlerInterfaces)
|
|
{
|
|
var genericArgs = registration.InterfaceType.GetGenericArguments();
|
|
var commandType = genericArgs[0];
|
|
var handlerType = registration.HandlerType;
|
|
|
|
if (genericArgs.Length == 1)
|
|
{
|
|
// ICommandHandler<TCommand>
|
|
RegisterCommandHandler(services, commandType, handlerType, null, lifetime);
|
|
}
|
|
else if (genericArgs.Length == 2)
|
|
{
|
|
// ICommandHandler<TCommand, TResult>
|
|
var resultType = genericArgs[1];
|
|
RegisterCommandHandler(services, commandType, handlerType, resultType, lifetime);
|
|
}
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scans the specified assembly and registers all query handlers found.
|
|
/// </summary>
|
|
/// <param name="services">The service collection</param>
|
|
/// <param name="assembly">The assembly to scan for query handlers</param>
|
|
/// <param name="filter">Optional filter to include/exclude specific handler types</param>
|
|
/// <param name="lifetime">Service lifetime for handlers (default: Transient)</param>
|
|
/// <returns>The service collection for chaining</returns>
|
|
public static IServiceCollection AddQueriesFromAssembly(
|
|
this IServiceCollection services,
|
|
Assembly assembly,
|
|
Func<Type, bool>? filter = null,
|
|
ServiceLifetime lifetime = ServiceLifetime.Transient)
|
|
{
|
|
var queryHandlerInterfaces = assembly.GetTypes()
|
|
.Where(type => type.IsClass && !type.IsAbstract && !type.IsGenericTypeDefinition)
|
|
.Where(type => filter == null || filter(type))
|
|
.SelectMany(handlerType => handlerType.GetInterfaces()
|
|
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryHandler<,>))
|
|
.Select(interfaceType => new { HandlerType = handlerType, InterfaceType = interfaceType }))
|
|
.ToList();
|
|
|
|
foreach (var registration in queryHandlerInterfaces)
|
|
{
|
|
var genericArgs = registration.InterfaceType.GetGenericArguments();
|
|
var queryType = genericArgs[0];
|
|
var resultType = genericArgs[1];
|
|
var handlerType = registration.HandlerType;
|
|
|
|
RegisterQueryHandler(services, queryType, resultType, handlerType, lifetime);
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
private static void RegisterCommandHandler(
|
|
IServiceCollection services,
|
|
Type commandType,
|
|
Type handlerType,
|
|
Type? resultType,
|
|
ServiceLifetime lifetime)
|
|
{
|
|
// Register handler with DI
|
|
Type serviceType;
|
|
if (resultType == null)
|
|
{
|
|
// ICommandHandler<TCommand>
|
|
serviceType = typeof(ICommandHandler<>).MakeGenericType(commandType);
|
|
}
|
|
else
|
|
{
|
|
// ICommandHandler<TCommand, TResult>
|
|
serviceType = typeof(ICommandHandler<,>).MakeGenericType(commandType, resultType);
|
|
}
|
|
|
|
services.Add(new ServiceDescriptor(serviceType, handlerType, lifetime));
|
|
|
|
// Register metadata for discovery
|
|
var commandMeta = resultType == null
|
|
? new CommandMeta(commandType, serviceType)
|
|
: new CommandMeta(commandType, serviceType, resultType);
|
|
|
|
services.AddSingleton<ICommandMeta>(commandMeta);
|
|
}
|
|
|
|
private static void RegisterQueryHandler(
|
|
IServiceCollection services,
|
|
Type queryType,
|
|
Type resultType,
|
|
Type handlerType,
|
|
ServiceLifetime lifetime)
|
|
{
|
|
// Register handler with DI
|
|
var serviceType = typeof(IQueryHandler<,>).MakeGenericType(queryType, resultType);
|
|
services.Add(new ServiceDescriptor(serviceType, handlerType, lifetime));
|
|
|
|
// Register metadata for discovery
|
|
var queryMeta = new QueryMeta(queryType, serviceType, resultType);
|
|
services.AddSingleton<IQueryMeta>(queryMeta);
|
|
}
|
|
} |