C# Academy · Lesson

Notifications and Events

Publish domain events with MediatR.

Lesson 4 of 413 steps

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-forget

INotification

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 inventory

Publish 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 broker

Testing 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:

  • INotification is a broadcast with zero or more INotificationHandlers.
  • Publish with IPublisher.Publish to 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.

Free to start

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

  1. CQRS Concepts
  2. Commands and Handlers with MediatR
  3. Pipeline Behaviors
  4. Notifications and Events
← Back to C# Academy