diff --git a/dotnet/AipsCore/Application/Abstract/IDispatcher.cs b/dotnet/AipsCore/Application/Abstract/IDispatcher.cs new file mode 100644 index 0000000..4cf5e44 --- /dev/null +++ b/dotnet/AipsCore/Application/Abstract/IDispatcher.cs @@ -0,0 +1,12 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Abstract.Query; + +namespace AipsCore.Application.Abstract; + +public interface IDispatcher +{ + Task Execute(ICommand command, CancellationToken cancellationToken = default); + Task Execute(ICommand command, CancellationToken cancellationToken = default); + + Task Execute(IQuery query, CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Dispatcher/DispatchException.cs b/dotnet/AipsCore/Application/Common/Dispatcher/DispatchException.cs new file mode 100644 index 0000000..8e0c9c9 --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Dispatcher/DispatchException.cs @@ -0,0 +1,11 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Abstract.Query; + +namespace AipsCore.Application.Common.Dispatcher; + +public class DispatchException : Exception +{ + public DispatchException(object commandQuery) + : base($"Error while dispatching '{commandQuery.GetType().Name}'") + { } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Common/Dispatcher/Dispatcher.cs b/dotnet/AipsCore/Application/Common/Dispatcher/Dispatcher.cs new file mode 100644 index 0000000..98c76f9 --- /dev/null +++ b/dotnet/AipsCore/Application/Common/Dispatcher/Dispatcher.cs @@ -0,0 +1,71 @@ +using AipsCore.Application.Abstract; +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Abstract.Query; +using Microsoft.Extensions.DependencyInjection; + +namespace AipsCore.Application.Common.Dispatcher; + +public sealed class Dispatcher : IDispatcher +{ + private readonly IServiceProvider _serviceProvider; + + public Dispatcher(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + #region Execute + + public async Task Execute(ICommand command, CancellationToken cancellationToken = default) + { + var handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType()); + + await this.Handle(handlerType, command, cancellationToken); + } + + public async Task Execute(ICommand command, CancellationToken cancellationToken = default) + { + var handlerType = typeof(ICommandHandler<,>).MakeGenericType(command.GetType(), typeof(TResult)); + + return await this.HandleWithResult(handlerType, command, cancellationToken); + } + + public async Task Execute(IQuery query, CancellationToken cancellationToken = default) + { + var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult)); + + return await this.HandleWithResult(handlerType, query, cancellationToken); + } + + #endregion + + #region Handle + + private async Task Handle(Type handlerType, object commandOrQuery, CancellationToken cancellationToken = default) + { + dynamic handler = this.ResolveHandler(handlerType, commandOrQuery); + + await handler.Handle((dynamic)commandOrQuery, cancellationToken); + } + + private async Task HandleWithResult(Type handlerType, object commandOrQuery, CancellationToken cancellationToken = default) + { + dynamic handler = this.ResolveHandler(handlerType, commandOrQuery); + + return await handler.Handle((dynamic)commandOrQuery, cancellationToken); + } + + #endregion + + private dynamic ResolveHandler(Type handlerType, object commandOrQuery) + { + dynamic? handler = _serviceProvider.GetService(handlerType); + + if (handler is null) + { + throw new DispatchException(commandOrQuery); + } + + return handler; + } +} \ No newline at end of file