https://github.com/jbogard/MediatR/wiki#basics
MediatR是一种进程内消息传递机制。 支持以同步或异步的形式进行请求/响应,命令,查询,通知和事件的消息传递,并通过C#泛型支持消息的智能调度。
Basics
MediatR has two kinds of messages it dispatches:
- Request/response messages, dispatched to a single handler
- Notification messages, dispatched to multiple handlers
Request/response
https://github.com/jbogard/MediatR/blob/master/test/MediatR.Tests/SendTests.cs
The request/response interface handles both command and query scenarios. First, create a message:
public class Ping : IRequest<string> { }
Next, create a handler:
public class PingHandler : IRequestHandler<Ping, string>
{
public Task<string> Handle(Ping request, CancellationToken cancellationToken)
{
return Task.FromResult("Pong");
}
}
Finally, send a message through the mediator:
var response = await mediator.Send(new Ping());
Debug.WriteLine(response); // "Pong"
https://github.com/jbogard/MediatR/blob/master/src/MediatR/Mediator.cs#L29
mediator会找到对应的handler,并且调用Handle方法,返回调用结果
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var requestType = request.GetType(); var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType, t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse)))); return handler.Handle(request, cancellationToken, _serviceFactory); }
In the case your message does not require a response消息不需要应答,也就是没有返回值, use the AsyncRequestHandler<TRequest>
base class:
public class OneWay : IRequest { }
public class OneWayHandlerWithBaseClass : AsyncRequestHandler<OneWay>
{
protected override Task Handle(OneWay request, CancellationToken cancellationToken)
{
// Twiddle thumbs
}
}
Or if the request is completely synchronous请求是完全同步的, inherit from the base RequestHandler
class:
public class SyncHandler : RequestHandler<Ping, string>
{
protected override string Handle(Ping request)
{
return "Pong";
}
}
Request types
There are two flavors of requests in MediatR - ones that return a value, and ones that do not:
IRequest<T>
- the request returns a valueIRequest
- the request does not return a value
To simplify the execution pipeline, IRequest
inherits IRequest<Unit>
where Unit
represents a terminal/ignored return type.
/// <summary> /// Represents a void type, since <see cref="System.Void"/> is not a valid return type in C#. /// </summary> public struct Unit : IEquatable<Unit>, IComparable<Unit>, IComparable
Each request type has its own handler interface, as well as some helper base classes:
IRequestHandler<T, U>
- implement this and returnTask<U>
RequestHandler<T, U>
- inherit this and returnU
public interface IRequestHandler<in TRequest, TResponse> where TRequest : 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); }
public abstract class RequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse> where TRequest : 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> protected abstract TResponse Handle(TRequest request); }
Then for requests without return values:
IRequestHandler<T>
- implement this and you will returnTask<Unit>
.AsyncRequestHandler<T>
- inherit this and you will returnTask
.RequestHandler<T>
- inherit this and you will return nothing (void
).
Notifications
https://github.com/jbogard/MediatR/blob/master/test/MediatR.Tests/PublishTests.cs
For notifications, first create your notification message:
public class Ping : INotification { }
Next, create zero or more handlers for your notification:
public class Pong1 : INotificationHandler<Ping>
{
public Task Handle(Ping notification, CancellationToken cancellationToken)
{
Debug.WriteLine("Pong 1");
return Task.CompletedTask;
}
}
public class Pong2 : INotificationHandler<Ping>
{
public Task Handle(Ping notification, CancellationToken cancellationToken)
{
Debug.WriteLine("Pong 2");
return Task.CompletedTask;
}
}
Finally, publish your message via the mediator:
await mediator.Publish(new Ping());
public Task Publish(object notification, CancellationToken cancellationToken = default) { if (notification == null) { throw new ArgumentNullException(nameof(notification)); } if (notification is INotification instance) { return PublishNotification(instance, cancellationToken); } throw new ArgumentException($"{nameof(notification)} does not implement ${nameof(INotification)}"); } 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))); return handler.Handle(notification, cancellationToken, _serviceFactory, PublishCore); }
Publish strategies
The default implementation of Publish loops through the notification handlers and awaits each one. This ensures each handler is run after one another.
Depending on your use-case for publishing notifications, you might need a different strategy for handling the notifications. Maybe you want to publish all notifications in parallel, or wrap each notification handler with your own exception handling logic.
A few example implementations can be found in MediatR.Examples.PublishStrategies. This shows four different strategies documented on the PublishStrategy enum.
https://www.cnblogs.com/sheng-jie/p/10280336.html
IPipelineBehavior
MeidatR支持按需配置请求管道进行消息处理。即支持在请求处理前和请求处理后添加额外行为。仅需实现以下两个接口,并注册到Ioc容器即可。
- IRequestPreProcessor 请求处理前接口
- IRequestPostProcessor<in TRequest, in TResponse> 请求处理后接口
其中IPipelineBehavior
的默认实现:RequestPreProcessorBehavior
和RequestPostProcessorBehavior
分别用来处理所有实现IRequestPreProcessor
和IRequestPostProcessor
接口定义的管道行为。
而处理管道是如何构建的呢?我们来看下RequestHandlerWrapperImpl
的具体实现