DEV Community

Chethan Ramaswamy
Chethan Ramaswamy

Posted on

Designing a Scalable Notification System using .NET, Azure Service Bus, MediatR, and SignalR

Why I’m Writing This

In one of my recent projects, we had a fairly common requirement on paper:

“Send notifications when something happens.”

But as usual, the reality was more complex:

  1. Notifications had to be real-time
  2. System needed to scale
  3. Multiple consumers (email, UI, future integrations)
  4. And most importantly — no tight coupling

I’ve seen systems break because notifications were treated as a “side feature”. So I thought I’d share how I approached designing this properly.

The Problem with the “Simple” Approach

The first instinct is usually something like:

API → Save to DB → Send Email / Notification

Looks fine initially. But over time:

Every feature starts calling notification logic directly
Adding a new channel (SMS, push) becomes painful
Failures in notification start impacting core business flow

I’ve been there — it doesn’t scale well.

How I Think About It

I try to separate concerns clearly:

  1. Business action happens (Order placed, Payment done)
  2. System emits an event
  3. Other parts of the system react to it

That naturally leads to an event-driven approach.

The Architecture I Use

At a high level:

Each component has a very specific responsibility.

Where MediatR Fits

Inside the API, I use MediatR mainly for decoupling.

Instead of controllers directly calling services:

  1. Controller sends a command
  2. Handler processes it
  3. Business logic stays clean and testable

It also gives me a clean place to hook in things like logging, validation, etc.

Why Azure Service Bus

Once the business action is completed (say, order created), I don’t send notifications directly.

I publish an event.

That’s where Azure Service Bus comes in:

  1. Decouples producer and consumer
  2. Handles retries, failures
  3. Lets multiple consumers subscribe

Today it might be just email + UI. Tomorrow it could be analytics, audit, external systems.

I don’t want to rewrite my core logic for that.

SignalR for Real-Time

For user-facing updates, polling is not a great experience.

That’s where SignalR helps:

  1. Server pushes updates instantly
  2. Works well for dashboards, alerts, chat-like scenarios

In our case, once the notification service processes an event, it pushes updates to connected clients.

End-to-End Flow (How It Actually Runs)

  1. User places an order
  2. API receives request
  3. MediatR handler processes and saves it
  4. Event gets published to Service Bus
  5. Notification service picks it up
  6. Sends email + pushes real-time update via SignalR

The important part:
👉 Order creation does not depend on notification success

Trade-offs (Because Nothing Is Free)

This approach is not “simple”:

  1. More moving parts
  2. Requires monitoring (Service Bus, consumers)
  3. Slight delay (eventual consistency)

But in return, you get:

  1. Scalability
  2. Flexibility
  3. Cleaner architecture

For me, that trade-off is worth it in most real systems.

Where This Works Really Well

I’ve seen this pattern work nicely in:

  1. E-commerce systems
  2. Banking alerts
  3. Monitoring dashboards
  4. Any system with user-triggered events + multiple consumers Final Thoughts

One thing I’ve learned over time:

Notifications should be treated as a separate system, not a side-effect.

Using MediatR, Service Bus, and SignalR together helped me keep things:

  1. Decoupled
  2. Scalable
  3. Easier to evolve

If you’ve built something similar or approached it differently, I’d be interested to hear your thoughts. Always good to compare patterns and learn.

dotnet #azure #systemdesign #microservices #softwarearchitecture

Top comments (0)