項目中使用了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
關鍵字
不爲寫博客而寫博客。記錄,一方面梳理和整理本身的所學和思路,另外一方面在之後遇到一樣問題時,而沒必要再花費沒必要要的時間。