ASP.NET Core 消息传递:MediatR
MediatR[1] 是參考中介者模式實現的一個 .NET 工具類庫,支持在進程內以單播或多播的形式進行消息傳遞,通過使用 MediatR 可實現消息的發送和處理充分解耦。
在介紹 MediatR 之前,先簡單了解下中介者模式。中介者模式主要是指定義一個中介對象來調度一系列對象之間的交互關系,各對象之間不需要顯式的相互引用,降低耦合性。如下對比圖(普通模式與中介者模式的區別):
實際上從 MediatR 源代碼中可以看出,它本身也并非標準中介者模式的實現,所以這里簡單了解即可。接下來將先介紹 MediatR 的兩種消息傳遞方式的使用方式,然后再分析其具體實現。
創建一個 .NET Core Web API 項目并安裝 MediatR.Extensions.Microsoft.DependencyInjection NuGet 包(已含 MediatR NuGet ?包),然后在 ConfigureServices 中注冊服務。
// 掃描 Startup 所在程序集內實現了 Handler 的對象并添加到 IoC 容器中 services.AddMediatR(typeof(Startup));可通過查看 MediatR.Extensions.Microsoft.DependencyInjection[2] ?說明了解 AddMediatR 具體包含了哪些服務的注冊以及各注冊對象的生命周期,基本通過以上一行代碼就已經把 MediatR 相關的服務全部注冊到 IoC 容器中。
單播消息傳遞
單播消息傳遞主要涉及 IRequest(消息類型) 和 IRequestHandler(消息處理) 兩個接口。
定義接口 IRequest 的實現類,string 指定消息處理方法的返回值類型,如下:
public class GenericRequest : IRequest<string> {public string Name { get; set; } }定義接口 IRequestHandler 的實現類,GenericRequest 指定此 Handler 要處理的消息類型,string 指定消息處理方法的返回值類型(與 IRequest 指定的泛型類型一致),另外需實現 Handle 方法,如下:
public class GenericRequestHandler : IRequestHandler<GenericRequest, string> {public Task<string> Handle(GenericRequest request, CancellationToken cancellationToken){return Task.FromResult($"This is {request.Name}");} }在 Controller 中進行調用測試:
private readonly IMediator _mediator;public MediatorController(IMediator mediator) {_mediator = mediator; }[HttpGet] public async Task<string> GenericRequest() {var result = await _mediator.Send(new GenericRequest{Name = "GenericRequest"});return result; }另外針對不同的代碼實現方式,有其他的 request-types[3] 可選,本質上還是基于 IRequest 和 IRequestHandler 的擴展。
多播消息傳遞
多播消息傳遞主要涉及 INotification(消息類型) 和 INotificationHandler(消息處理) 兩個接口,另外多播消息傳遞是無返回值的。
定義接口 INotification 的實現類,如下:
public class GenericNotification : INotification {public string Name { get; set; } }定義接口 INotificationHandler 的實現類,GenericNotification 指定此 Handler 要處理的消息類型,另外需實現 Handle 方法,這里將為此消息類型定義兩個 NotificationHandler 實現類,如下:
public class GenericANotificationHandler : INotificationHandler<GenericNotification> {public Task Handle(GenericNotification notification, CancellationToken cancellationToken){Console.WriteLine($"A {notification.Name}");return Task.CompletedTask;} } public class GenericBNotificationHandler : INotificationHandler<GenericNotification> {public Task Handle(GenericNotification notification, CancellationToken cancellationToken){Console.WriteLine($"B {notification.Name}");return Task.CompletedTask;} }在 Controller 中進行調用測試:
[HttpGet] public async Task GenericNotification() {await _mediator.Publish(new GenericNotification{Name = "GenericNotification"}); }原理分析
建議閱讀下源碼,代碼量少且結構清晰,基本理解沒什么難度
通過前面的介紹可以了解在 MediatR 中面向開發者的核心接口主要是 IRequest&IRequestHandler 、INotification&INotificationHandler、IMediator 。
如下 IMediator ?的實現類 Mediator 中的定義:
public class Mediator : IMediator {private readonly ServiceFactory _serviceFactory;private static readonly ConcurrentDictionary<Type, object> _requestHandlers = new ConcurrentDictionary<Type, object>();private static readonly ConcurrentDictionary<Type, NotificationHandlerWrapper> _notificationHandlers = new ConcurrentDictionary<Type, NotificationHandlerWrapper>(); }首先定義了 ServiceFactory 對象,它代表當前應用程序的 IoC 容器,在應用初始化階段進行了注入,如 MediatR.Extensions.Microsoft.DependencyInjection 已包含了對應的 ServiceFactory 注冊[4]。由于 ServiceFactory 可自定義,所以開發中也完全可以選擇其他的含 IoC 容器功能的框架,如 Autofac、Castle Windsor、DryIoc 等。
另外定義 _requestHandlers 和 _notificationHandlers 分別保存單播和多播消息對象類型對應的 HandlerWrapper 對象,HandlerWrapper 的主要是對 ServiceFactory 對象的傳遞,最終通過 ServiceFactory 從 IoC 容器中獲取對應消息類型的 Handler 對象。
MeidatR 還支持為單播消息定義消息處理的 Pipeline,如通過實現 IRequestPreProcessor 、IRequestPostProcessor 在消息處理前后自定義處理行為,通過實現 IRequestExceptionHandler、IRequestExceptionAction 在異常時自定義處理行為,這些實現類也是通過 ServiceFactory 從 IoC 容器中獲取。
以下是單播消息處理的核心代碼:
public override Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken, ServiceFactory serviceFactory) {Task<TResponse> Handler() => GetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory).Handle((TRequest) request, cancellationToken);return serviceFactory.GetInstances<IPipelineBehavior<TRequest, TResponse>>().Reverse().Aggregate((RequestHandlerDelegate<TResponse>) Handler, (next, pipeline) => () => pipeline.Handle((TRequest)request, cancellationToken, next))(); }首先從 ServiceFactory 獲取 IPipelineBehavior,然后通 Linq 的 Reverse 方法進行順序顛倒,最后通過 Aggregate 進行委托傳遞并執行,所以最終執行順序是 RequestPreProcessorBehavior → ?Handler → RequestPostProcessorBehavior,這里的實現可能較難理解,核心是 Aggregate 的使用。
總結
MediatR 在實現上核心是通過保存消息請求對象與消息處理對象的關系,配合 IoC 容器實現的消息傳遞解耦。在實際應用中,通過 MediatR 多播消息傳遞可以使代碼實現邏輯上更加簡潔,另外也有較多的文章介紹了通過 ?MediatR 實現 CQRS、EventBus 等。
參考資料
[1]
MediatR: https://github.com/jbogard/MediatR
[2]MediatR.Extensions.Microsoft.DependencyInjection: https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection
[3]request-types: https://github.com/jbogard/MediatR/wiki#request-types
[4]ServiceFactory 注冊: https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection/blob/master/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs#L219
總結
以上是生活随笔為你收集整理的ASP.NET Core 消息传递:MediatR的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kubernetes+Azure Dev
- 下一篇: ERP平台的自动化测试技术实践