项目中使用了CQRS读写分离,增删改 的地方使用了
MediatR
,将进程内消息的发送和处理进行解耦。因而便有了这篇文章,整理并记录一下本身的学习。遇到问题,解决问题,记录问题,成长就是一步一步走出来的。c#
MediatR
是什么?是的,无论你怎么翻译都查不到该词,好多人都猜想说是做者将Mediator笔误写成MediatR了,哈哈哈,该问题暂且不论。asp.net
做者说这是一个野心很小的库,试图解决一个问题———解耦进程内消息的发送与处理。异步
Asp.Net Core 咱们可使用扩展了 Microsoft.Extensions.DependencyInjection
的 MediatR
的扩展包 MediatR.Extensions.Microsoft.DependencyInjection
,方便直接注册服务。async
安装该Nuget包,会自动安装MediatR
。写文档时使用的版本:v7.0.0
ide
Package Manager : Install-Package MediatR.Extensions.Microsoft.DependencyInjection 或 CLI : dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
v7.0.0版本学习
services.AddMediatR(typeof(MyHandler)); 或 services.AddMediatR(typeof(Startup).GetTypeInfo().Assembly); //这里用的Startup,其实Hanler所在的项目中的任何一个文件均可
若是使用的是 v6.0.1
版本时 只须要 services.AddMediatR()
便可。.net
MediatR
有两种方式的消息发送方式:翻译
Request
/Response
(请求/响应消息),指派到 一个 处理程序Notification
(广播消息),指派到 多个 处理程序也就是一个消息对应一个消息处理。code
请求和响应接口处理命令和查询场景,首先,建立一个消息:继承
public class CreateUserCommand : IRequest<string> { public string Name { get; set; } }
而后建立一个处理器:
public class CreateUserHandler : IRequestHandler<CreateUserCommand, string> { public async Task<string> Handle(CreateUserCommand request, CancellationToken cancellationToken) { return await Task.FromResult($"New name is {request.Name}"); } }
最后,经过 mediator 发送消息:
[HttpPost("User")] public async Task<string> CreateUserAsync([FromQuery] string name) { var response = await _mediator.Send(new CreateUserCommand { Name = name}); return response; }
若是你的消息不须要返回响应消息,可使用 AsyncRequestHandler<TRequest>
基础类:
//消息 public class NoResponseCommand : IRequest { } //处理器 public class NoResponseHandler : AsyncRequestHandler<NoResponseCommand> { protected override async Task Handle(NoResponseCommand request, CancellationToken cancellationToken) { //handle the logic } } //接口 [HttpPost("NoResponse")] public async Task NoResponseAsync() { await _mediator.Send(new NoResponseCommand()); }
在 MediatR
中有两种请求类型。一种有返回值,一种没有返回值。
IRequest<T>
:该请求会返回一个值IRequest
:该请求没有返回值为了简化执行管道,IRequest
继承了IRequest<Unit>
接口,其中 Unit
表明了一个终端或可忽略的返回类型。
每一个请求类型都有属于本身对应的处理器接口:
IRequestHandler<T,U>
:实现它,并返回 Task<U>
.RequestHandler<T,U>
:继承它,并返回 Task<U>
.而后是对于那些没有返回值的请求的处理器接口:
IRequestHandler<T>
:实现它,并返回 Task<Unit>
.AsyncRequestHandler<T>
:继承它,并返回 Task
.RequestHandler<T>
:继承它,什么也不用返回 ( void
)也就是发布一个消息,会有多个消息处理器进行消息处理。
对于广播,首先要建立你的广播消息:
public class MyNotificationCommand: INotification { /// <summary> /// 广播的内容 /// </summary> public string Message { get; set; } }
接下来建立0个或多个处理器来处理广播:
public class FirstMyNotificationHandler : INotificationHandler<MyNotificationCommand> { public async Task Handle(MyNotificationCommand notification, CancellationToken cancellationToken) { //针对广播的内容作进一步处理 Debug.WriteLineIf(!string.IsNullOrEmpty(notification.Message), $"First notification handler:{notification.Message}"); } } public class SecondMyNotificationHandler : INotificationHandler<MyNotificationCommand> { public async Task Handle(MyNotificationCommand notification, CancellationToken cancellationToken) { //针对广播的内容作进一步处理 Debug.WriteLineIf(!string.IsNullOrEmpty(notification.Message), $"Second notification handler:{notification.Message}"); } }
最后经过 mediator 发布消息。
[HttpPost("Publish")] public async Task PublishNotificationAsync([FromQuery] string name) { await _mediator.Publish(new MyNotificationCommand {Message = name }); }
以上代码会在输出栏打印 First和Second 两次的内容。
Send/Publish在 IMediatR
端都是异步的,只要你的工做是能够等待的,你的处理器就可使用Async
或await
关键字
不为写博客而写博客。记录,一方面梳理和整理本身的所学和思路,另外一方面在之后遇到一样问题时,而没必要再花费没必要要的时间。