[{"data":1,"prerenderedAt":631},["ShallowReactive",2],{"page-\u002Fcsharp\u002Fmediatr的消息机制原理":3},{"id":4,"title":5,"body":6,"description":624,"extension":625,"meta":626,"navigation":113,"path":627,"seo":628,"stem":629,"__hash__":630},"content\u002Fcsharp\u002FMediatR的消息机制原理.md","MediatR的消息机制原理",{"type":7,"value":8,"toc":618},"minimark",[9,22,29,42,45,50,61,121,124,135,150,171,178,182,185,200,204,211,250,253,267,271,282,378,381,401,416,420,428,431,434,440,443,446,449,497,501,504,524,527,530,556,559,562,584,588,591,611,614],[10,11,12,13,17,18,21],"p",{},"MediatR 库是建立在 ",[14,15,16],"strong",{},"C# 接口","和 ",[14,19,20],{},".NET Core 依赖注入 (DI)"," 容器之上的。它利用 DI 容器的生命周期管理和类型解析能力，实现了清晰的请求路由机制，它是一个典型的中介者模式的实现。发送者和接受者都不需要直接引用彼此，消息完全是在进程内传递，无需外部依赖，所有的通信都在进程里完成。并且通过了IMediator接口来统一处理请求\u002F响应和流式请求。",[10,23,24,28],{},[25,26,27],"code",{},"Mediator"," 类作为中介者,负责:",[30,31,32,36,39],"ul",{},[33,34,35],"li",{},"接收请求并路由到相应的处理器 Mediator.cs:45-60",[33,37,38],{},"发布通知到所有订阅的处理器 Mediator.cs:116-125",[33,40,41],{},"创建和管理流式请求 Mediator.cs:158-175",[10,43,44],{},"MediatR 支持以下几种主要的消息处理方式:",[46,47,49],"h3",{"id":48},"_1-requestresponse-请求响应","1. Request\u002FResponse (请求\u002F响应)",[10,51,52,53,56,57,60],{},"这是最常见的处理方式,用于发送请求并获取响应，是单播模式，每个请求只会被一个处理器给处理从实现上可以看到,",[25,54,55],{},"Send"," 方法会解析请求类型并获取",[14,58,59],{},"单个","对应的处理器: Mediator.cs:52-59",[62,63,68],"pre",{"className":64,"code":65,"language":66,"meta":67,"style":67},"language-csharp shiki shiki-themes github-light github-dark","        var handler = (RequestHandlerWrapper\u003CTResponse>)_requestHandlers.GetOrAdd(request.GetType(), static requestType =>\n        {\n            var wrapperType = typeof(RequestHandlerWrapperImpl\u003C,>).MakeGenericType(requestType, typeof(TResponse));\n            var wrapper = Activator.CreateInstance(wrapperType) ?? throw new InvalidOperationException($\"Could not create wrapper type for {requestType}\");\n            return (RequestHandlerBase)wrapper;\n        });\n\n        return handler.Handle(request, _serviceProvider, cancellationToken);\n","csharp","",[25,69,70,78,84,90,96,102,108,115],{"__ignoreMap":67},[71,72,75],"span",{"class":73,"line":74},"line",1,[71,76,77],{},"        var handler = (RequestHandlerWrapper\u003CTResponse>)_requestHandlers.GetOrAdd(request.GetType(), static requestType =>\n",[71,79,81],{"class":73,"line":80},2,[71,82,83],{},"        {\n",[71,85,87],{"class":73,"line":86},3,[71,88,89],{},"            var wrapperType = typeof(RequestHandlerWrapperImpl\u003C,>).MakeGenericType(requestType, typeof(TResponse));\n",[71,91,93],{"class":73,"line":92},4,[71,94,95],{},"            var wrapper = Activator.CreateInstance(wrapperType) ?? throw new InvalidOperationException($\"Could not create wrapper type for {requestType}\");\n",[71,97,99],{"class":73,"line":98},5,[71,100,101],{},"            return (RequestHandlerBase)wrapper;\n",[71,103,105],{"class":73,"line":104},6,[71,106,107],{},"        });\n",[71,109,111],{"class":73,"line":110},7,[71,112,114],{"emptyLinePlaceholder":113},true,"\n",[71,116,118],{"class":73,"line":117},8,[71,119,120],{},"        return handler.Handle(request, _serviceProvider, cancellationToken);\n",[10,122,123],{},"。 README.md:13",[10,125,126,127,130,131,134],{},"关键在于 ",[25,128,129],{},"GetRequiredService\u003CIRequestHandler\u003CTRequest, TResponse>>()"," ",[14,132,133],{},"只会返回一个处理器实例",": RequestHandlerWrapper.cs:37-38",[62,136,138],{"className":64,"code":137,"language":66,"meta":67,"style":67}," Task\u003CTResponse> Handler(CancellationToken t = default) => serviceProvider.GetRequiredService\u003CIRequestHandler\u003CTRequest, TResponse>>()\n            .Handle((TRequest) request, t == default ? cancellationToken : t);\n",[25,139,140,145],{"__ignoreMap":67},[71,141,142],{"class":73,"line":74},[71,143,144],{}," Task\u003CTResponse> Handler(CancellationToken t = default) => serviceProvider.GetRequiredService\u003CIRequestHandler\u003CTRequest, TResponse>>()\n",[71,146,147],{"class":73,"line":80},[71,148,149],{},"            .Handle((TRequest) request, t == default ? cancellationToken : t);\n",[30,151,152,162],{},[33,153,154,157,158,161],{},[14,155,156],{},"带返回值的请求",": 实现 ",[25,159,160],{},"IRequestHandler\u003CTRequest, TResponse>"," 接口 README.md:63",[33,163,164,157,167,170],{},[14,165,166],{},"无返回值的请求",[25,168,169],{},"IRequestHandler\u003CTRequest>"," 接口 README.md:64",[10,172,173,174,177],{},"通过 ",[25,175,176],{},"IMediator.Send()"," 方法发送请求: Mediator.cs:45-60",[46,179,181],{"id":180},"_2-notifications-通知","2. Notifications (通知)",[10,183,184],{},"用于发布事件通知,支持多个处理器同时处理同一个通知，这个是消息总线里最常用的方式，也就是订阅者发布者模式，是一种多播模式。 README.md:13",[30,186,187,194],{},[33,188,189,190,193],{},"实现 ",[25,191,192],{},"INotificationHandler\u003CTNotification>"," 接口 README.md:65",[33,195,173,196,199],{},[25,197,198],{},"IMediator.Publish()"," 方法发布通知 Mediator.cs:116-120",[46,201,203],{"id":202},"_3-stream-requests-流式请求","3. Stream Requests (流式请求)",[10,205,206,207,210],{},"用于处理返回异步流的请求,",[14,208,209],{},"支持流式数据处理","，它的使用场景是需要处理大量的数据的时候，流式请求可以逐条返回结果而不是一次项加载所有数据到内存，适合用于日志、监控数据等情况。",[62,212,214],{"className":64,"code":213,"language":66,"meta":67,"style":67},"   public class PingStreamHandler : IStreamRequestHandler\u003CPing, Pong>\n    {\n        public async IAsyncEnumerable\u003CPong> Handle(Ping request, [EnumeratorCancellation]CancellationToken cancellationToken)\n        {\n            yield return await Task.Run(() => new Pong { Message = request.Message + \" Pang\" });\n        }\n    }\n",[25,215,216,221,226,231,235,240,245],{"__ignoreMap":67},[71,217,218],{"class":73,"line":74},[71,219,220],{},"   public class PingStreamHandler : IStreamRequestHandler\u003CPing, Pong>\n",[71,222,223],{"class":73,"line":80},[71,224,225],{},"    {\n",[71,227,228],{"class":73,"line":86},[71,229,230],{},"        public async IAsyncEnumerable\u003CPong> Handle(Ping request, [EnumeratorCancellation]CancellationToken cancellationToken)\n",[71,232,233],{"class":73,"line":92},[71,234,83],{},[71,236,237],{"class":73,"line":98},[71,238,239],{},"            yield return await Task.Run(() => new Pong { Message = request.Message + \" Pang\" });\n",[71,241,242],{"class":73,"line":104},[71,243,244],{},"        }\n",[71,246,247],{"class":73,"line":110},[71,248,249],{},"    }\n",[10,251,252],{},"。 README.md:35",[30,254,255,261],{},[33,256,189,257,260],{},[25,258,259],{},"IStreamRequestHandler\u003CTRequest, TResponse>"," 接口 README.md:66",[33,262,173,263,266],{},[25,264,265],{},"IMediator.CreateStream()"," 方法创建流 CreateStreamTests.cs:51",[46,268,270],{"id":269},"_4-pipeline-behaviors-管道行为","4. Pipeline Behaviors (管道行为)",[10,272,273,274,277,278,281],{},"用于",[14,275,276],{},"实现横切关注点,如日志记录、验证、事务处理等","，它允许您在",[14,279,280],{},"请求处理前后插入额外的逻辑","。",[62,283,285],{"className":64,"code":284,"language":66,"meta":67,"style":67},"    public class OuterBehavior : IPipelineBehavior\u003CPing, Pong>\n    {\n        private readonly Logger _output;\n\n        public OuterBehavior(Logger output)\n        {\n            _output = output;\n        }\n\n        public async Task\u003CPong> Handle(Ping request, RequestHandlerDelegate\u003CPong> next, CancellationToken cancellationToken)\n        {\n            _output.Messages.Add(\"Outer before\");\n            var response = await next();\n            _output.Messages.Add(\"Outer after\");\n\n            return response;\n        }\n    }\n",[25,286,287,292,296,301,305,310,314,319,323,328,334,339,345,351,357,362,368,373],{"__ignoreMap":67},[71,288,289],{"class":73,"line":74},[71,290,291],{},"    public class OuterBehavior : IPipelineBehavior\u003CPing, Pong>\n",[71,293,294],{"class":73,"line":80},[71,295,225],{},[71,297,298],{"class":73,"line":86},[71,299,300],{},"        private readonly Logger _output;\n",[71,302,303],{"class":73,"line":92},[71,304,114],{"emptyLinePlaceholder":113},[71,306,307],{"class":73,"line":98},[71,308,309],{},"        public OuterBehavior(Logger output)\n",[71,311,312],{"class":73,"line":104},[71,313,83],{},[71,315,316],{"class":73,"line":110},[71,317,318],{},"            _output = output;\n",[71,320,321],{"class":73,"line":117},[71,322,244],{},[71,324,326],{"class":73,"line":325},9,[71,327,114],{"emptyLinePlaceholder":113},[71,329,331],{"class":73,"line":330},10,[71,332,333],{},"        public async Task\u003CPong> Handle(Ping request, RequestHandlerDelegate\u003CPong> next, CancellationToken cancellationToken)\n",[71,335,337],{"class":73,"line":336},11,[71,338,83],{},[71,340,342],{"class":73,"line":341},12,[71,343,344],{},"            _output.Messages.Add(\"Outer before\");\n",[71,346,348],{"class":73,"line":347},13,[71,349,350],{},"            var response = await next();\n",[71,352,354],{"class":73,"line":353},14,[71,355,356],{},"            _output.Messages.Add(\"Outer after\");\n",[71,358,360],{"class":73,"line":359},15,[71,361,114],{"emptyLinePlaceholder":113},[71,363,365],{"class":73,"line":364},16,[71,366,367],{},"            return response;\n",[71,369,371],{"class":73,"line":370},17,[71,372,244],{},[71,374,376],{"class":73,"line":375},18,[71,377,249],{},[10,379,380],{},"README.md:76-87",[30,382,383,392],{},[33,384,385,157,388,391],{},[14,386,387],{},"Pipeline Behavior",[25,389,390],{},"IPipelineBehavior\u003CTRequest, TResponse>"," 接口 Program.cs:33-37",[33,393,394,157,397,400],{},[14,395,396],{},"Stream Pipeline Behavior",[25,398,399],{},"IStreamPipelineBehavior\u003CTRequest, TResponse>"," 接口 README.md:82",[10,402,403,404,407,408,411,412,415],{},"流式管道行为使用 ",[25,405,406],{},"IAsyncEnumerable"," 来处理",[14,409,410],{},"流数据",",可以在",[14,413,414],{},"流的开始和结束时添加额外的项目","，类似于一个洋葱模型。",[417,418,419],"h4",{"id":419},"具体类型注册",[62,421,426],{"className":422,"code":424,"language":425},[423],"language-text","cfg.AddBehavior\u003CIPipelineBehavior\u003CPing, Pong>, OuterBehavior>();\n","text",[25,427,424],{"__ignoreMap":67},[10,429,430],{},"MediatrServiceConfiguration.cs:151-163",[417,432,433],{"id":433},"开放泛型注册",[62,435,438],{"className":436,"code":437,"language":425},[423],"cfg.AddOpenBehavior(typeof(GenericBehavior\u003C,>));\n",[25,439,437],{"__ignoreMap":67},[10,441,442],{},"MediatrServiceConfiguration.cs:202-229",[10,444,445],{},"开放泛型行为会应用到所有匹配的请求类型。",[417,447,448],{"id":448},"常见使用场景",[450,451,452,461,470,476,485,491],"ol",{},[33,453,454,457,458],{},[14,455,456],{},"日志记录",": 记录",[14,459,460],{},"请求和响应",[33,462,463,466,467],{},[14,464,465],{},"验证",": 在处理前",[14,468,469],{},"验证请求数据",[33,471,472,475],{},[14,473,474],{},"事务管理",": 包装处理器在事务中",[33,477,478,481,482],{},[14,479,480],{},"性能监控",": 测量",[14,483,484],{},"处理时间",[33,486,487,490],{},[14,488,489],{},"缓存",": 缓存响应结果",[33,492,493,496],{},[14,494,495],{},"异常处理",": 统一处理异常",[417,498,500],{"id":499},"prepost-processors-前置后置处理器","Pre\u002FPost Processors (前置\u002F后置处理器)",[10,502,503],{},"用于在请求处理前后执行额外逻辑。 README.md:83-84",[30,505,506,515],{},[33,507,508,157,511,514],{},[14,509,510],{},"Pre-Processor",[25,512,513],{},"IRequestPreProcessor\u003CTRequest>"," 接口 Program.cs:38",[33,516,517,157,520,523],{},[14,518,519],{},"Post-Processor",[25,521,522],{},"IRequestPostProcessor\u003CTRequest, TResponse>"," 接口 Program.cs:39-40",[417,525,526],{"id":526},"内置管道行为",[10,528,529],{},"MediatR 提供了几个内置的管道行为:",[30,531,532,538,544,550],{},[33,533,534,537],{},[25,535,536],{},"RequestPreProcessorBehavior\u003CTRequest, TResponse>",": 执行前置处理器 Program.cs:58",[33,539,540,543],{},[25,541,542],{},"RequestPostProcessorBehavior\u003CTRequest, TResponse>",": 执行后置处理器 RequestPostProcessorBehavior.cs:7-31",[33,545,546,549],{},[25,547,548],{},"RequestExceptionProcessorBehavior\u003CTRequest, TResponse>",": 处理异常 Program.cs:61",[33,551,552,555],{},[25,553,554],{},"RequestExceptionActionProcessorBehavior\u003CTRequest, TResponse>",": 执行异常动作 Program.cs:59-60",[417,557,558],{"id":558},"约束泛型行为",[10,560,561],{},"您可以创建带有类型约束的泛型行为,使其只应用于特定类型: PipelineTests.cs:198-217",[10,563,564,565,568,569,572,573,576,577,572,580,583],{},"这个 ",[25,566,567],{},"ConstrainedBehavior"," 只会应用于 ",[25,570,571],{},"TRequest"," 是 ",[25,574,575],{},"Ping"," 且 ",[25,578,579],{},"TResponse",[25,581,582],{},"Pong"," 的请求。 PipelineTests.cs:570-635",[417,585,587],{"id":586},"exception-handling-异常处理","Exception Handling (异常处理)",[10,589,590],{},"提供结构化的异常处理机制。",[30,592,593,602],{},[33,594,595,157,598,601],{},[14,596,597],{},"Exception Handler",[25,599,600],{},"IRequestExceptionHandler\u003CTRequest, TResponse, TException>"," 接口,可以捕获异常并提供替代响应 README.md:67",[33,603,604,157,607,610],{},[14,605,606],{},"Exception Action",[25,608,609],{},"IRequestExceptionAction\u003CTRequest, TException>"," 接口,用于执行副作用(如日志记录),但不能阻止异常传播 README.md:68",[10,612,613],{},"管道行为的执行顺序很重要,先注册的行为会在外层,后注册的在内层。所有管道行为都是通过依赖注入容器自动解析的,可以在构造函数中注入其他服务。",[615,616,617],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":67,"searchDepth":80,"depth":80,"links":619},[620,621,622,623],{"id":48,"depth":86,"text":49},{"id":180,"depth":86,"text":181},{"id":202,"depth":86,"text":203},{"id":269,"depth":86,"text":270},"MediatR 库是建立在 C# 接口和 .NET Core 依赖注入 (DI) 容器之上的。它利用 DI 容器的生命周期管理和类型解析能力，实现了清晰的请求路由机制，它是一个典型的中介者模式的实现。发送者和接受者都不需要直接引用彼此，消息完全是在进程内传递，无需外部依赖，所有的通信都在进程里完成。并且通过了IMediator接口来统一处理请求\u002F响应和流式请求。","md",{},"\u002Fcsharp\u002Fmediatr的消息机制原理",{"description":624},"csharp\u002FMediatR的消息机制原理","ilElciLkpy7-HorUovG2XKiZwMUnidFuzhx66Z90494",1791042465225]