namespace GainCapital.Execution.DealingManager.Infrastructure.CqrsExtensions { public class CqrsDispatcher : ICqrsDispatcher { private static readonly ConcurrentDictionary QueryDispatchers = new ConcurrentDictionary(); private static readonly ConcurrentDictionary CommandDispatchers = new ConcurrentDictionary(); private readonly IServiceProvider _serviceProvider; private readonly IHttpContextAccessor _httpContextAccessor; public CqrsDispatcher(IServiceProvider serviceProvider, IHttpContextAccessor httpContextAccessor) { _serviceProvider = serviceProvider; _httpContextAccessor = httpContextAccessor; } public Task DispatchAsync(IQuery query) { var queryDispatcher = QueryDispatchers.GetOrAdd(query.GetType(), queryType => { var makeGenericType = typeof(QueryDispatcher<,>).MakeGenericType(queryType, typeof(TResult)); return (QueryDispatcherBase)Activator.CreateInstance(makeGenericType)!; }); var cancellationToken = _httpContextAccessor.HttpContext?.RequestAborted; return (Task)queryDispatcher.Dispatch(query, _serviceProvider, cancellationToken ?? default); } public Task DispatchAsync(ICommand command) where TResult : CSharpFunctionalExtensions.IResult { var commandDispatcher = CommandDispatchers.GetOrAdd(command.GetType(), commandType => { var makeGenericType = typeof(CommandDispatcher<,>).MakeGenericType(commandType, typeof(TResult)); return (CommandDispatcherBase)Activator.CreateInstance(makeGenericType)!; }); var cancellationToken = _httpContextAccessor.HttpContext?.RequestAborted; return (Task)commandDispatcher.Dispatch(command, _serviceProvider, cancellationToken ?? default); } } internal abstract class QueryDispatcherBase { public abstract object Dispatch(object query, IServiceProvider serviceProvider, CancellationToken cancellationToken); } internal class QueryDispatcher : QueryDispatcherBase where TQuery : IQuery { public override object Dispatch(object query, IServiceProvider serviceProvider, CancellationToken cancellationToken) { return Dispatch((TQuery)query, serviceProvider, cancellationToken); } private static async Task Dispatch(TQuery query, IServiceProvider serviceProvider, CancellationToken cancellationToken) { using var serviceScope = serviceProvider.CreateScope(); var queryHandler = serviceScope.ServiceProvider.GetRequiredService>(); return await queryHandler.Handle(query, cancellationToken); } } internal abstract class CommandDispatcherBase { public abstract object Dispatch(object command, IServiceProvider serviceProvider, CancellationToken cancellationToken); } internal class CommandDispatcher : CommandDispatcherBase where TCommand : ICommand where TResult : CSharpFunctionalExtensions.IResult { public override object Dispatch(object command, IServiceProvider serviceProvider, CancellationToken cancellationToken) { return Dispatch((TCommand)command, serviceProvider, cancellationToken); } private static async Task Dispatch(TCommand command, IServiceProvider serviceProvider, CancellationToken cancellationToken) { using var serviceScope = serviceProvider.CreateScope(); var queryHandler = serviceScope.ServiceProvider.GetRequiredService>(); return await queryHandler.HandleAsync(command, cancellationToken); } } }