通知与事件
使用 MediatR 发布领域事件。
通知与事件 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。
请求与通知
请求只有一个 handler,并且会返回一个值。通知是一种广播:它有零个或多个 handler,并且不返回任何内容。请使用通知来宣布某件事情已经发生。
// Request: one handler, returns a result
// Notification: many handlers, fire-and-forgetINotification
领域事件是实现 INotification 的记录。它描述的是过去发生的事实。
public record OrderPlacedNotification(int OrderId, int CustomerId)
: INotification;通知处理器
每个订阅者都会实现 INotificationHandler<TNotification>。多个处理器可以订阅同一个通知,并且彼此独立地处理该通知。
public class SendConfirmationEmailHandler
: INotificationHandler<OrderPlacedNotification>
{
public Task Handle(
OrderPlacedNotification n, CancellationToken ct)
{
// send the email...
return Task.CompletedTask;
}
}多个订阅者
您可以根据需要添加任意数量的处理器。它们互不了解,因此无需修改发布者即可添加新的响应。
public class UpdateInventoryHandler
: INotificationHandler<OrderPlacedNotification>
{
public Task Handle(OrderPlacedNotification n, CancellationToken ct)
{
// decrement stock...
return Task.CompletedTask;
}
}发布
若要发出通知,请注入 IPublisher(或 IMediator),然后调用 Publish。每个已注册的处理器都会被调用。
public class CreateOrderHandler(AppDbContext db, IPublisher publisher)
: IRequestHandler<CreateOrderCommand, int>
{
public async Task<int> Handle(CreateOrderCommand c, CancellationToken ct)
{
var order = new Order { CustomerId = c.CustomerId };
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
await publisher.Publish(
new OrderPlacedNotification(order.Id, c.CustomerId), ct);
return order.Id;
}
}解耦副作用
通知可以让主要用例保持专注。创建 order 时只需记录订单并发布事件;发送电子邮件和更新库存则分别放在各自的处理器中。这正是开闭原则的实际应用。
// CreateOrderHandler does NOT know about email or inventory发布策略
默认情况下,MediatR 会按顺序等待每个通知处理器。如果某个处理器抛出异常,后续处理器将不会运行。您可以提供自定义 publisher,让它们并行运行。
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.NotificationPublisher = new TaskWhenAllPublisher();
});处理失败
由于各处理器彼此独立,因此请明确失败的含义。对于非关键的副作用,请在 handler 内捕获异常并记录日志,以免一个失败影响其他处理器。
public async Task Handle(OrderPlacedNotification n, CancellationToken ct)
{
try { await _email.SendAsync(n.CustomerId, ct); }
catch (Exception ex) { _logger.LogError(ex, "email failed"); }
}领域事件模式
一种常见模式是:实体收集领域事件,在事务保存完成后统一发布这些事件。这样可以确保只有在更改提交后才触发事件。
await db.SaveChangesAsync(ct);
foreach (var domainEvent in order.Events)
await publisher.Publish(domainEvent, ct);
order.Events.Clear();通知与消息队列
MediatR 通知在进程内运行,并且在请求范围内是同步的。如果需要跨服务传递或持久化投递,请改为发布到真正的消息代理(例如 RabbitMQ、Azure Service Bus)。
// In-process reactions -> MediatR notifications
// Cross-service / durable -> message broker测试通知
您可以传入模拟的 IPublisher,并断言其已被调用,从而验证某个处理器是否发布了正确的事件。
var publisher = new Mock<IPublisher>();
var handler = new CreateOrderHandler(db, publisher.Object);
await handler.Handle(new CreateOrderCommand(1, []), default);
publisher.Verify(p => p.Publish(
It.IsAny<OrderPlacedNotification>(), default), Times.Once);快速检查
确认您对通知模型的理解。
回顾
您已经学习了通知和事件:
INotification是一种广播,可以有零个或多个INotificationHandler。- 使用
IPublisher.Publish发布通知,以调用所有订阅者。 - 通知可以解耦副作用,并遵循开闭原则。
- 通知在进程内运行;对于跨服务或需要持久化的事件,请使用消息代理。
CQRS 和 MediatR 课程到此完成。
常见问题解答
「通知与事件」课时是免费的吗?
是的 — 「通知与事件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。
「通知与事件」这节课中我会学到什么?
使用 MediatR 发布领域事件。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C# Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「通知与事件」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C# Academy 课中编写并运行代码吗?
能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。