asp.net core 使用 mediatr
项目中使用了cqrs读写分离,增删改 的地方使用了
mediatr
,将进程内消息的发送和处理进行解耦。于是便有了这篇文章,整理并记录一下自己的学习。遇到问题,解决问题,记录问题,成长就是一步一步走出来的。
mediatr
是什么?
是的,不管你怎么翻译都查不到该词,好多人都猜测说是作者将mediator笔误写成mediatr了,哈哈哈,该问题暂且不论。
作者说这是一个野心很小的库,试图解决一个问题———解耦进程内消息的发送与处理。
一、下载nuget包
asp.net core 我们可以使用扩展了 microsoft.extensions.dependencyinjection
的 mediatr
的扩展包 mediatr.extensions.microsoft.dependencyinjection
,方便直接注册服务。
安装该nuget包,会自动安装mediatr
。写文档时使用的版本:v7.0.0
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()
即可。
三、基本使用
mediatr
有两种方式的消息发送方式:
request
/response
(请求/响应消息),指派到 一个 处理程序notification
(广播消息),指派到 多个 处理程序
请求和响应(消息单播)
也就是一个消息对应一个消息处理。
请求和响应接口处理命令和查询场景,首先,创建一个消息:
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
关键字
不为写博客而写博客。记录,一方面梳理和整理自己的所学和思路,另一方面在以后遇到同样问题时,而不必再花费不必要的时间。