Notifications and Events
Publish domain events with MediatR.
Notifications and Events is a free C# Academy lesson on CoddyKit. This is lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, and your progress syncs across the web and the CoddyKit app. The C# Academy course includes 4 lessons in total.
Requests vs Notifications
A request has one handler and returns a value. A notification is a broadcast: it has zero or more handlers and returns nothing. Use notifications to announce that something happened.
// Request: one handler, returns a result
// Notification: many handlers, fire-and-forgetINotification
A domain event is a record implementing INotification. It describes a fact in the past tense.
public record OrderPlacedNotification(int OrderId, int CustomerId)
: INotification;INotificationHandler
Each subscriber implements INotificationHandler<TNotification>. Many handlers can subscribe to the same notification, each handling it independently.
public class SendConfirmationEmailHandler
: INotificationHandler<OrderPlacedNotification>
{
public Task Handle(
OrderPlacedNotification n, CancellationToken ct)
{
// send the email...
return Task.CompletedTask;
}
}Multiple Subscribers
Add as many handlers as you need. None of them know about the others - new reactions can be added without touching the publisher.
public class UpdateInventoryHandler
: INotificationHandler<OrderPlacedNotification>
{
public Task Handle(OrderPlacedNotification n, CancellationToken ct)
{
// decrement stock...
return Task.CompletedTask;
}
}Publishing
To raise a notification, inject IPublisher (or IMediator) and call Publish. Every registered handler is invoked.
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;
}
}Decoupling Side Effects
Notifications keep the main use case focused. Placing an order just records the order and publishes an event; emailing and inventory live in their own handlers. This is the open/closed principle in action.
// CreateOrderHandler does NOT know about email or inventoryPublish Strategy
By default MediatR awaits each notification handler sequentially. If one throws, later handlers do not run. You can supply a custom publisher to run them in parallel.
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
cfg.NotificationPublisher = new TaskWhenAllPublisher();
});Handling Failures
Because handlers are independent, decide what a failure means. For non-critical side effects, catch and log inside the handler so one failure does not break the others.
public async Task Handle(OrderPlacedNotification n, CancellationToken ct)
{
try { await _email.SendAsync(n.CustomerId, ct); }
catch (Exception ex) { _logger.LogError(ex, "email failed"); }
}Domain Events Pattern
A common pattern: entities collect domain events, and after saving the transaction you publish them all. This guarantees events fire only when the change is committed.
await db.SaveChangesAsync(ct);
foreach (var domainEvent in order.Events)
await publisher.Publish(domainEvent, ct);
order.Events.Clear();Notifications vs Message Queues
MediatR notifications are in-process and synchronous within the request. For cross-service or durable delivery, publish to a real message broker (e.g. RabbitMQ, Azure Service Bus) instead.
// In-process reactions -> MediatR notifications
// Cross-service / durable -> message brokerTesting Notifications
You can verify a handler publishes the right event by passing a mock IPublisher and asserting it was called.
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);Quick Check
Confirm the notification model.
Recap
You learned notifications and events:
INotificationis a broadcast with zero or moreINotificationHandlers.- Publish with
IPublisher.Publishto invoke all subscribers. - Notifications decouple side effects and follow the open/closed principle.
- They are in-process; use a broker for cross-service or durable events.
That completes the CQRS and MediatR course.
Learn C# with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 93
- Lessons
- 346
Frequently Asked Questions
Is the “Notifications and Events” lesson free?
Yes — the full text of “Notifications and Events” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO. The C# Academy course includes 4 lessons in total.
What will I learn in “Notifications and Events”?
Publish domain events with MediatR. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C# Academy?
No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.
How long does the “Notifications and Events” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C# Academy lesson?
Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- CQRS Concepts
- Commands and Handlers with MediatR
- Pipeline Behaviors
- Notifications and Events