///<summary> /// Marker interface to represent a request with a void response ///</summary> publicinterfaceIRequest : IRequest<Unit> { }
///<summary> /// Marker interface to represent a request with a response ///</summary> ///<typeparam name="TResponse">Response type</typeparam> publicinterfaceIRequest<outTResponse> : IBaseRequest { }
///<summary> /// Allows for generic type constraints of objects implementing IRequest or IRequest{TResponse} ///</summary> publicinterfaceIBaseRequest { }
///<summary> /// Defines a handler for a request ///</summary> ///<typeparam name="TRequest">The type of request being handled</typeparam> ///<typeparam name="TResponse">The type of response from the handler</typeparam> publicinterfaceIRequestHandler<inTRequest, TResponse> whereTRequest : IRequest<TResponse> { ///<summary> /// Handles a request ///</summary> ///<param name="request">The request</param> ///<param name="cancellationToken">Cancellation token</param> ///<returns>Response from the request</returns> Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken); }
///<summary> /// Defines a handler for a request with a void (<see cref="Unit" />) response. /// You do not need to register this interface explicitly with a container as it inherits from the base <see cref="IRequestHandler{TRequest, TResponse}" /> interface. ///</summary> ///<typeparam name="TRequest">The type of request being handled</typeparam> publicinterfaceIRequestHandler<inTRequest> : IRequestHandler<TRequest, Unit> whereTRequest : IRequest<Unit> { }
///<summary> /// Wrapper class for a handler that asynchronously handles a request and does not return a response ///</summary> ///<typeparam name="TRequest">The type of request being handled</typeparam> publicabstractclassAsyncRequestHandler<TRequest> : IRequestHandler<TRequest> whereTRequest : IRequest { async Task<Unit> IRequestHandler<TRequest, Unit>.Handle(TRequest request, CancellationToken cancellationToken) { await Handle(request, cancellationToken).ConfigureAwait(false); return Unit.Value; }
///<summary> /// Override in a derived class for the handler logic ///</summary> ///<param name="request">Request</param> ///<param name="cancellationToken"></param> ///<returns>Response</returns> protectedabstract Task Handle(TRequest request, CancellationToken cancellationToken); }
///<summary> /// Wrapper class for a handler that synchronously handles a request and returns a response ///</summary> ///<typeparam name="TRequest">The type of request being handled</typeparam> ///<typeparam name="TResponse">The type of response from the handler</typeparam> publicabstractclassRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse> whereTRequest : IRequest<TResponse> { Task<TResponse> IRequestHandler<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken) => Task.FromResult(Handle(request));
///<summary> /// Override in a derived class for the handler logic ///</summary> ///<param name="request">Request</param> ///<returns>Response</returns> protectedabstract TResponse Handle(TRequest request); }
///<summary> /// Wrapper class for a handler that synchronously handles a request does not return a response ///</summary> ///<typeparam name="TRequest">The type of request being handled</typeparam> publicabstractclassRequestHandler<TRequest> : IRequestHandler<TRequest> whereTRequest : IRequest { Task<Unit> IRequestHandler<TRequest, Unit>.Handle(TRequest request, CancellationToken cancellationToken) { Handle(request); return Unit.Task; }
///<summary> /// Override in a derived class for the handler logic ///</summary> ///<param name="notification">Notification</param> protectedabstractvoidHandle(TNotification notification); }
///<summary> /// Represents an async continuation for the next task to execute in the pipeline ///</summary> ///<typeparam name="TResponse">Response type</typeparam> ///<returns>Awaitable task returning a <typeparamref name="TResponse"/></returns> publicdelegateTask<TResponse> RequestHandlerDelegate<TResponse>();
///<summary> /// Pipeline behavior to surround the inner handler. /// Implementations add additional behavior and await the next delegate. ///</summary> ///<typeparam name="TRequest">Request type</typeparam> ///<typeparam name="TResponse">Response type</typeparam> publicinterfaceIPipelineBehavior<inTRequest, TResponse> whereTRequest : notnull { ///<summary> /// Pipeline handler. Perform any additional behavior and await the <paramref name="next"/> delegate as necessary ///</summary> ///<param name="request">Incoming request</param> ///<param name="cancellationToken">Cancellation token</param> ///<param name="next">Awaitable delegate for the next action in the pipeline. Eventually this delegate represents the handler.</param> ///<returns>Awaitable task returning the <typeparamref name="TResponse"/></returns> Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next); }
publicinterfaceIMediator { ///<summary> /// Asynchronously send a request to a single handler ///</summary> ///<typeparam name="TResponse">Response type</typeparam> ///<param name="request">Request object</param> ///<param name="cancellationToken">Optional cancellation token</param> ///<returns>A task that represents the send operation. The task result contains the handler response</returns> Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default);
///<summary> /// Asynchronously send an object request to a single handler via dynamic dispatch ///</summary> ///<param name="request">Request object</param> ///<param name="cancellationToken">Optional cancellation token</param> ///<returns>A task that represents the send operation. The task result contains the type erased handler response</returns> Task<object?> Send(object request, CancellationToken cancellationToken = default);
///<summary> /// Asynchronously send a notification to multiple handlers ///</summary> ///<param name="notification">Notification object</param> ///<param name="cancellationToken">Optional cancellation token</param> ///<returns>A task that represents the publish operation.</returns> Task Publish(object notification, CancellationToken cancellationToken = default);
///<summary> /// Asynchronously send a notification to multiple handlers ///</summary> ///<param name="notification">Notification object</param> ///<param name="cancellationToken">Optional cancellation token</param> ///<returns>A task that represents the publish operation.</returns> Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification; }
///<summary> /// Initializes a new instance of the <see cref="Mediator"/> class. ///</summary> ///<param name="serviceFactory">The single instance factory.</param> publicMediator(ServiceFactory serviceFactory) { _serviceFactory = serviceFactory; }
var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType, t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));
public Task<object?> Send(object request, CancellationToken cancellationToken = default) { if (request == null) { thrownew ArgumentNullException(nameof(request)); } var requestType = request.GetType(); var requestInterfaceType = requestType .GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequest<>)); var isValidRequest = requestInterfaceType != null;
if (!isValidRequest) { thrownew ArgumentException($"{nameof(request)} does not implement ${nameof(IRequest)}"); }
var responseType = requestInterfaceType!.GetGenericArguments()[0]; var handler = _requestHandlers.GetOrAdd(requestType, t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, responseType)));
// call via dynamic dispatch to avoid calling through reflection for performance reasons return ((RequestHandlerBase) handler).Handle(request, cancellationToken, _serviceFactory); }
public Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification { if (notification == null) { thrownew ArgumentNullException(nameof(notification)); }
public Task Publish(object notification, CancellationToken cancellationToken = default) { if (notification == null) { thrownew ArgumentNullException(nameof(notification)); } if (notification is INotification instance) { return PublishNotification(instance, cancellationToken); }
thrownew ArgumentException($"{nameof(notification)} does not implement ${nameof(INotification)}"); }
///<summary> /// Override in a derived class to control how the tasks are awaited. By default the implementation is a foreach and await of each handler ///</summary> ///<param name="allHandlers">Enumerable of tasks representing invoking each notification handler</param> ///<param name="notification">The notification being published</param> ///<param name="cancellationToken">The cancellation token</param> ///<returns>A task representing invoking all handlers</returns> protectedvirtualasync Task PublishCore(IEnumerable<Func<INotification, CancellationToken, Task>> allHandlers, INotification notification, CancellationToken cancellationToken) { foreach (var handler in allHandlers) { await handler(notification, cancellationToken).ConfigureAwait(false); } }
private Task PublishNotification(INotification notification, CancellationToken cancellationToken = default) { var notificationType = notification.GetType(); var handler = _notificationHandlers.GetOrAdd(notificationType, t => (NotificationHandlerWrapper)Activator.CreateInstance(typeof(NotificationHandlerWrapperImpl<>).MakeGenericType(notificationType)));
///<summary> /// Factory method used to resolve all services. For multiple instances, it will resolve against <see cref="IEnumerable{T}" /> ///</summary> ///<param name="serviceType">Type of service to resolve</param> ///<returns>An instance of type <paramref name="serviceType" /></returns> publicdelegateobjectServiceFactory(Type serviceType);
publicstaticclassServiceFactoryExtensions { publicstatic T GetInstance<T>(this ServiceFactory factory)=> (T) factory(typeof(T));
publicstaticIEnumerable<T> GetInstances<T>(this ServiceFactory factory) { Type type = typeof(IEnumerable<T>);
var a = (IEnumerable<T>) factory.Invoke(typeof(IEnumerable<T>));
try { handler = factory.GetInstance<THandler>(); } catch (Exception e) { thrownew InvalidOperationException($"Error constructing handler for request of type {typeof(THandler)}. Register your handlers with the container. See the samples in GitHub for examples.", e); }
if (handler == null) { thrownew InvalidOperationException($"Handler was not found for request of type {typeof(THandler)}. Register your handlers with the container. See the samples in GitHub for examples."); }
///<summary> /// Override in a derived class to control how the tasks are awaited. By default the implementation is a foreach and await of each handler ///</summary> ///<param name="allHandlers">Enumerable of tasks representing invoking each notification handler</param> ///<param name="notification">The notification being published</param> ///<param name="cancellationToken">The cancellation token</param> ///<returns>A task representing invoking all handlers</returns> protectedvirtualasync Task PublishCore(IEnumerable<Func<INotification, CancellationToken, Task>> allHandlers, INotification notification, CancellationToken cancellationToken) { foreach (var handler in allHandlers) { await handler(notification, cancellationToken).ConfigureAwait(false); } }