MediatR-程序內的訊息通訊框架
MediatR是一款程序內的訊息訂閱、釋出框架,提供了Send方法用於釋出到單個處理程式、Publish方法釋出到多個處理程式,使用起來非常方便。目前支援 .NET Framework4.5、.NET Stardand1.3、.NET Stardand2.0等版本,可跨平臺使用。
使用MediatR
要在專案中使用MediatR,首先要新增引用:nuget install MediatR
在使用MediatR的時候,需要設定一個容器來例項化所有的Handler,因此我們需要與依賴注入框架結合使用,MediatR支援目前主流的依賴注入框架,例如Autofac等,也可以直接使用 .NET Core 的依賴注入框架。
如果使用 .net core的依賴注入,將MediatR新增到容器將會很方便:
services.AddMediatR(typeof(Program).Assembly);
如果是多個程式集,如果是多個程式集:
services.AddMediatR(typeof(Program).Assembly, typeof(HelloWorld).Assembly);
MediatR有兩種訊息處理模式:
- Request/Response模式:Message將被單個Handler處理,可以有返回值
- Notifictaion模式:Message可以被多個Handler處理,無返回值
Request/Response模式
使用起來很簡單,首先定義Request訊息,方法如下:
public class Ping : IRequest<string> { }
然後,定義它的處理程式:
public class PingHandler : IRequestHandler<Ping, string> { public Task<string> Handle(Ping request, CancellationToken cancellationToken) { return Task.FromResult("Pong"); } }
這樣就可以了,我們在控制檯傳送Ping訊息:
var response = await mediator.Send(new Ping());
Console.WriteLine(response); // "Pong"
無返回值的訊息
當處理訊息不需要返回值時,我們應該使用如下方式定義訊息:
public class Ping : IRequest { }
對應的訊息處理程式如下:
public class PingHandler: AsyncRequestHandler<Ping> {
protected override Task Handle(Ping request, CancellationToken cancellationToken) {
// todo...
}
}
同步的訊息處理
預設情況下訊息的處理都是非同步的(返回值為Task物件),如果你想要同步執行訊息,需要按下面的方式定義訊息處理程式:
public class PingHandler : RequestHandler<Ping, string> {
protected override string Handle(Ping request) {
return "Pong";
}
}
這種模式符合CQRS中Command的處理方式,一個Command只能有一個Handler,因此,在使用CQRS時可以參考。
Notification 模式
Notification模式將訊息釋出給多個處理程式,訊息的處理沒有返回值。
訊息的定義:
public class HelloWorld : INotification
{
}
多個處理程式:
public class CNReply : INotificationHandler<HelloWorld>
{
public Task Handle(HelloWorld notification, CancellationToken cancellationToken)
{
Console.WriteLine($"CN Reply: Hello from CN");
return Task.CompletedTask;
}
}
public class USReply : INotificationHandler<HelloWorld>
{
public Task Handle(HelloWorld notification, CancellationToken cancellationToken)
{
Console.WriteLine($"US Reply: Hello from US");
return Task.CompletedTask;
}
}
然後通過Publish方法釋出訊息:
await mediator.Publish(helloworld);
釋出策略
預設情況下,MediatR的訊息釋出是一個一個執行的,即便是返回Task的情況,也是使用await等待上一個執行完成後才進行下一個的呼叫。如果需要使用並行的方法進行呼叫,可以進行定製,具體可參考官方示例:MediatR.Examples.PublishStrategies
多型支援
MediatR訊息處理程式是支援逆變的,例如我們可以定義一個訊息監聽程式,監聽所有釋出的Notification:
public class MessageListener : INotificationHandler<INotification>
{
public Task Handle(INotification notification, CancellationToken cancellationToken)
{
Console.WriteLine($"接收到新的訊息:{notification.GetType()}");
return Task.CompletedTask;
}
}
對於IRequest型別的訊息,此種方式未驗證成功。如果可以的話,倒是可以做一個無處理程式的訊息的監聽,也是挺好玩的。
非同步
對於MediatR來說,無論是傳送IRequest型別訊息,還是釋出INotification型別訊息,都是非同步的。這裡需要特別留意,即使你使用的是同步的訊息處理程式,對於訊息釋出來說,都是非同步的,與你的處理程式是同步或非同步無關。
參考文件
- MediatR官方文件