MediatR
MediatR
是 .NET
中的开源简单中介者模式实现.它通过一种进程内消息传递机制(无其他外部依赖),进行请求/响应、命令、查询、通知和事件的消息传递,并通过泛型来支持消息的智能调度。开源库地址是 https://github.com/jbogard/MediatR
详细介绍,可见我之前的文章《MediatR 在 .NET 应用中的实践》
MediatR 10.0
2022年1月7日,MediatR 的作者发布了 10.0 。该版本主要有如下几个更新:
支持 Stream
即通过新的 IStreamRequest
来获得 IAsyncEnumerable
的响应结果; 可以通过类似下面的代码形式,定义 StreamRequest 和对应的 Handler
public class Sing : IStreamRequest<Song>
{
public string Message { get; set; }
}
public class Song
{
public string Message { get; set; }
}
public class SingHandler : IStreamRequestHandler<Sing, Song>
{
private readonly TextWriter _writer;
public SingHandler(TextWriter writer)
{
_writer = writer;
}
public async IAsyncEnumerable<Song> Handle(Sing request, [EnumeratorCancellation]CancellationToken cancellationToken)
{
await _writer.WriteLineAsync($"--- Handled Sing: {request.Message}, Song");
yield return await Task.Run(() => new Song { Message = request.Message + "ing do" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing re" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing mi" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing fa" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing so" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing la" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing ti" });
yield return await Task.Run(() => new Song { Message = request.Message + "ing do" });
}
}
然后我们就用通过异步 foreach 来进行调用了:
await foreach (Song s in mediator.CreateStream(new Sing { Message = "Sing" }))
{
// 根据流式响应的结果进行业务处理
}
也就是说这种 StreamRequest
我们需要通过 IMediator
的 CreateStream
方法来调用处理程序。
可以想到在一些需要异步跟踪长任务进度或者聊天交出程序等场景下蛮有用的。
新增一个独立的包 MediatR.Contracts
这样你就可以将 Request
/ Notification
/ StreamRequest
通过仅引用该包在一个独立的项目中定义,而将相关的 Handler
在另外一个项目中实现。例如下列场景:
- API contracts
- GRPC contracts
- Blazor
Break Changes
当我们从 9.x 版本 升级到 10.0 时,需要注意一下管线相关的定义要稍微修改一下,因为 IPipelineBehavior
接口中的泛型约束做了一点点修改。
IPipelineBehavior
的泛型约束 从where TRequest notnull
修改为where TRequest : IRequest<TResponse>
IRequestExceptionHandler
的泛型约束 从where TRequest notnull
修改为where TRequest : IRequest<TResponse>
IRequestPostProcessor
的泛型约束 从where TRequest notnull
修改为where TRequest : IRequest<TResponse>
IRequestPostProcessor
的泛型约束 从where TRequest notnull
修改为where TRequest : IRequest<TResponse>
所以,我们在使用 MediatR
的代码中如果有自定义的管线代码,需要在原来的基础上增加一点泛型约束即可,否则编译无法通过:
public class GenericPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
}