MediatR是什么?
MediatR
使用中介者模式来解耦类与类依赖的库,选用设计模式种经典的观察者模式。
MediatR
是怎么解决耦合的呢,就好比:两个人对话,使用一个第三者作为传声器
那么这个第三者就被成为终结者,两个人的对话就相当于订阅和发布。
单播通信
单播通信再MediatR
中主要使用IRequest
、Request
这两个抽象来作为单播通信的媒介,而使用IRequestHandler
、RequestHandler
、AsyncRequestHandler
作为单播通信媒介的订阅方。举个例子:
// 使用IRequest的单播通信媒介
public class Jing : IRequest
{
public string Message { get; set; }
}
// 媒介是Jing的单薄通信订阅方
public class JingHandler : AsyncRequestHandler<Jing>
{
protected override Task Handle(Jing request, CancellationToken cancellationToken)
{
Console.WriteLine($"--- Handled Jing: {request.Message}, no Jong");
return Task.CompletedTask;
}
}
// 发布
await mediator.Send(new Jing { Message = "Jing" });
单播通信是通常项目中解耦的手段之一,可实现两个类或类库完全解除依赖,两者通信靠MediatR
来完成,能有效地避免依赖注入时的循环依赖
问题
广播
广播在数据传输层面指的是在一条总线上一个主机的通信会传递到该总线下所有的其他主机。而在MediatR
中广播指的是订阅了同一个广播媒介的对象,主要使用INotification
作为广播订阅的媒介,而使用INotificationHandler
作为广播通信的处理程序,举个例子:
// 以INotification作为广播通信媒介
public class Pinged : INotification
{
public string Message { get; internal set; }
}
// 订阅方式1:指定广播媒介订阅
public class PingedHandler : INotificationHandler<Pinged>
{
public Task Handle(Pinged notification, CancellationToken cancellationToken)
{
Console.WriteLine("Got pinged async.");
return Task.CompletedTask;
}
}
// 订阅方式2:指定继承关系的广播媒介订阅
public class ConstrainedPingedHandler<TNotification> : INotificationHandler<TNotification>
where TNotification : Pinged
{
public Task Handle(TNotification notification, CancellationToken cancellationToken)
{
Console.WriteLine("Got pinged constrained async.");
return Task.CompletedTask;
}
}
广播可用来处理一个属性的变动会引发一系列的其他操作且这些操作并行存在,可以极大程度的降低耦合和依赖。
异常处理
MediatR
提供了在通信过程中(单播和广播不限),对于异常的处理方式。使用异常时需要提前向依赖注入的容器注入RequestExceptionActionProcessorBehavior
。MediatR
中对于异常的处理常用的有3个抽象,分别是AsyncRequestExceptionHandler<TRequest, TResponse>(异步处理所有类型的异常)
、RequestExceptionHandler<TRequest, TResponse, TException>(同步处理指定基类的异常)
、RequestExceptionHandler<TRequest, TResponse>(同步处理所有类型的异常)
,
public class GenericExceptionHadnler<TRequest, TResponse, TException> : RequestExceptionHandler<TRequest, TResponse, TException>
where TRequest : notnull
where TException : Exception
{
protected override void Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state)
{
Console.WriteLine(exception.Message);
}
}
以上三个抽象类实现的接口分别是IRequestExceptionHandler<in TRequest, TResponse, TException>(指定异常类型的处理接口)
、IRequestExceptionHandler<in TRequest, TResponse>(任意异常类型的处理接口)
管道
MediatR
提供了在通信之前和之后这条管道的AOP操作接口,分别是IRequestPreProcessor(通信前做的事)
、IRequestPostProcessor(通信后做的事)
,这两者使用之前需要将IPipelineBehavior
注册进管道;IPipelineBehavior对应处理前后在MediatR
有其抽象实现类分别是RequestPreProcessorBehavior
、RequestPostProcessorBehavior
,举个例子
// 定义自己对与管道的处理行为
public class GenericPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
Console.WriteLine("-- Handling Request");
var response = await next();
Console.WriteLine("-- Finished Request");
return response;
}
}
// 定义自己的通信前处理程序
public class GenericRequestPreProcessor<TRequest> : IRequestPreProcessor<TRequest>
{
public Task Process(TRequest request, CancellationToken cancellationToken)
{
Console.WriteLine("- Starting Up");
return Task.CompletedTask;
}
}
// 定义自己的通信前处理程序
public class GenericRequestPostProcessor<TRequest, TResponse> : IRequestPostProcessor<TRequest, TResponse>
{
public Task Process(TRequest request, TResponse response, CancellationToken cancellationToken)
{
Console.WriteLine("- Finished");
return Task.CompletedTask;
}
}
源码见:MediatR,
例子见:MediatR/Samples、