多年来,MediatR 一直是.NET 领域的明星工具。它通过中介者模式为复杂应用带来了清晰的解耦架构。需要跨层发送命令?触发通知?接入日志记录或验证等行为?MediatR 轻松实现这一切。
但最近,风向变了。
未来可能采用商业许可的传闻让我们团队陷入思考:如果核心应用逻辑被锁定在一个前景不明朗的库中,我们能否承受这种风险?
更深层的问题随之浮现: 我们真的还需要 MediatR 吗?
事实证明,.NET 的基类库(BCL)早已内置了我们所需的一切——甚至更多。
为何重新评估 MediatR? 🤔
许可不确定性
没有人希望基础库产生意外成本。从 MIT 协议转向商业许可的动向,不仅引发成本担忧,更关乎架构的长期控制权。
过度抽象的代价
MediatR 的优雅需付出代价:
• 管道(Pipelines)
• 装饰器(Decorators)
• 通知(Notifications)
即使简单的发布/订阅场景,对小团队和轻量级应用而言,抽象层似乎已超越实际收益。
控制力受限
需要自定义重试逻辑?死信队列?消息优先级?
要么硬编码扩展行为,要么费力调整库以适配需求。
✨ 原生替代方案:System.Threading.Channels
Channels —— .NET BCL 中的低调英雄。
最初为高吞吐量生产者/消费者场景设计,Channels 提供零依赖的高性能内存消息队列:无需魔法反射,完全掌控底层。
🛠️ 我们如何构建自有消息总线
internal sealed class InMemoryMessageQueue
{
private readonly Channel<IIntegrationEvent> _channel =
Channel.CreateUnbounded<IIntegrationEvent>();
public ChannelReader<IIntegrationEvent> Reader => _channel.Reader;
public ChannelWriter<IIntegrationEvent> Writer => _channel.Writer;
}
开箱即用的线程安全队列,原生支持背压(Backpressure)与取消令牌。
internal sealed class EventBus : IEventBus
{
private readonly InMemoryMessageQueue _queue;
public EventBus(InMemoryMessageQueue queue) =>
_queue = queue;
public async Task PublishAsync<T>(
T integrationEvent,
CancellationToken cancellationToken = default)
where T : class, IIntegrationEvent
{
await _queue.Writer.WriteAsync(integrationEvent, cancellationToken);
}
}
无装饰器、无 ServiceCollection 配置。仅关注写入与读取。
消费者端可运行简单后台服务,从通道读取并分发事件。
🎉 核心优势
✅ 零外部依赖
减少 NuGet 包 = 降低生产环境风险。代码自主可控,无需等待第三方维护更新。
✅ 完全透明
需添加日志?批处理?限流?
管道由你定义。无隐式行为注入,代码清晰可读。
✅ 经过验证的性能
Channels 驱动 ASP.NET Core 内核,专为高负载场景设计。
✅ 面向未来
即使 MediatR 或其他依赖转向,核心架构稳如磐石。你掌握底层控制权。
🚗 但这不是重复造轮子吗?
若依赖 MediatR 的完整功能集,或许如此。
但对简单命令派发或一次性通知,Channels 已足够:
• 通过有界通道实现背压
• 使用异步中间件实现重试与死信队列
• 代码量不足 50 行
差异在于:你并非重复发明轮子,而是跳过冗余步骤,直接构建更高效、更契合需求的解决方案。