ASP.NET Core 消息传递:MediatR
MediatR[1] 是參考中介者模式實(shí)現(xiàn)的一個(gè) .NET 工具類庫(kù),支持在進(jìn)程內(nèi)以單播或多播的形式進(jìn)行消息傳遞,通過使用 MediatR 可實(shí)現(xiàn)消息的發(fā)送和處理充分解耦。
在介紹 MediatR 之前,先簡(jiǎn)單了解下中介者模式。中介者模式主要是指定義一個(gè)中介對(duì)象來調(diào)度一系列對(duì)象之間的交互關(guān)系,各對(duì)象之間不需要顯式的相互引用,降低耦合性。如下對(duì)比圖(普通模式與中介者模式的區(qū)別):
實(shí)際上從 MediatR 源代碼中可以看出,它本身也并非標(biāo)準(zhǔn)中介者模式的實(shí)現(xiàn),所以這里簡(jiǎn)單了解即可。接下來將先介紹 MediatR 的兩種消息傳遞方式的使用方式,然后再分析其具體實(shí)現(xiàn)。
創(chuàng)建一個(gè) .NET Core Web API 項(xiàng)目并安裝 MediatR.Extensions.Microsoft.DependencyInjection NuGet 包(已含 MediatR NuGet ?包),然后在 ConfigureServices 中注冊(cè)服務(wù)。
// 掃描 Startup 所在程序集內(nèi)實(shí)現(xiàn)了 Handler 的對(duì)象并添加到 IoC 容器中 services.AddMediatR(typeof(Startup));可通過查看 MediatR.Extensions.Microsoft.DependencyInjection[2] ?說明了解 AddMediatR 具體包含了哪些服務(wù)的注冊(cè)以及各注冊(cè)對(duì)象的生命周期,基本通過以上一行代碼就已經(jīng)把 MediatR 相關(guān)的服務(wù)全部注冊(cè)到 IoC 容器中。
單播消息傳遞
單播消息傳遞主要涉及 IRequest(消息類型) 和 IRequestHandler(消息處理) 兩個(gè)接口。
定義接口 IRequest 的實(shí)現(xiàn)類,string 指定消息處理方法的返回值類型,如下:
public class GenericRequest : IRequest<string> {public string Name { get; set; } }定義接口 IRequestHandler 的實(shí)現(xiàn)類,GenericRequest 指定此 Handler 要處理的消息類型,string 指定消息處理方法的返回值類型(與 IRequest 指定的泛型類型一致),另外需實(shí)現(xiàn) Handle 方法,如下:
public class GenericRequestHandler : IRequestHandler<GenericRequest, string> {public Task<string> Handle(GenericRequest request, CancellationToken cancellationToken){return Task.FromResult($"This is {request.Name}");} }在 Controller 中進(jìn)行調(diào)用測(cè)試:
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; }另外針對(duì)不同的代碼實(shí)現(xiàn)方式,有其他的 request-types[3] 可選,本質(zhì)上還是基于 IRequest 和 IRequestHandler 的擴(kuò)展。
多播消息傳遞
多播消息傳遞主要涉及 INotification(消息類型) 和 INotificationHandler(消息處理) 兩個(gè)接口,另外多播消息傳遞是無返回值的。
定義接口 INotification 的實(shí)現(xiàn)類,如下:
public class GenericNotification : INotification {public string Name { get; set; } }定義接口 INotificationHandler 的實(shí)現(xiàn)類,GenericNotification 指定此 Handler 要處理的消息類型,另外需實(shí)現(xiàn) Handle 方法,這里將為此消息類型定義兩個(gè) NotificationHandler 實(shí)現(xiàn)類,如下:
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 中進(jìn)行調(diào)用測(cè)試:
[HttpGet] public async Task GenericNotification() {await _mediator.Publish(new GenericNotification{Name = "GenericNotification"}); }原理分析
建議閱讀下源碼,代碼量少且結(jié)構(gòu)清晰,基本理解沒什么難度
通過前面的介紹可以了解在 MediatR 中面向開發(fā)者的核心接口主要是 IRequest&IRequestHandler 、INotification&INotificationHandler、IMediator 。
如下 IMediator ?的實(shí)現(xiàn)類 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 對(duì)象,它代表當(dāng)前應(yīng)用程序的 IoC 容器,在應(yīng)用初始化階段進(jìn)行了注入,如 MediatR.Extensions.Microsoft.DependencyInjection 已包含了對(duì)應(yīng)的 ServiceFactory 注冊(cè)[4]。由于 ServiceFactory 可自定義,所以開發(fā)中也完全可以選擇其他的含 IoC 容器功能的框架,如 Autofac、Castle Windsor、DryIoc 等。
另外定義 _requestHandlers 和 _notificationHandlers 分別保存單播和多播消息對(duì)象類型對(duì)應(yīng)的 HandlerWrapper 對(duì)象,HandlerWrapper 的主要是對(duì) ServiceFactory 對(duì)象的傳遞,最終通過 ServiceFactory 從 IoC 容器中獲取對(duì)應(yīng)消息類型的 Handler 對(duì)象。
MeidatR 還支持為單播消息定義消息處理的 Pipeline,如通過實(shí)現(xiàn) IRequestPreProcessor 、IRequestPostProcessor 在消息處理前后自定義處理行為,通過實(shí)現(xiàn) IRequestExceptionHandler、IRequestExceptionAction 在異常時(shí)自定義處理行為,這些實(shí)現(xiàn)類也是通過 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 方法進(jìn)行順序顛倒,最后通過 Aggregate 進(jìn)行委托傳遞并執(zhí)行,所以最終執(zhí)行順序是 RequestPreProcessorBehavior → ?Handler → RequestPostProcessorBehavior,這里的實(shí)現(xiàn)可能較難理解,核心是 Aggregate 的使用。
總結(jié)
MediatR 在實(shí)現(xiàn)上核心是通過保存消息請(qǐng)求對(duì)象與消息處理對(duì)象的關(guān)系,配合 IoC 容器實(shí)現(xiàn)的消息傳遞解耦。在實(shí)際應(yīng)用中,通過 MediatR 多播消息傳遞可以使代碼實(shí)現(xiàn)邏輯上更加簡(jiǎn)潔,另外也有較多的文章介紹了通過 ?MediatR 實(shí)現(xiàn) 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 注冊(cè): https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection/blob/master/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs#L219
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core 消息传递:MediatR的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kubernetes+Azure Dev
- 下一篇: asp.net ajax控件工具集 Au