Controllers frequently take on too many responsibilities as ASP.NET Core applications expand, including managing HTTP requests, verifying input, carrying out business logic, and communicating with the data layer. Applications are more difficult to test, maintain, and expand due to this close dependency.
By directing requests through specialized handlers, the well-known library MediatR helps developers separate application components by implementing the Mediator paradigm. Applications that adhere to CQRS and Clean Architecture principles make extensive use of it.
But not all issues can be resolved with MediatR. Although it makes code more organized, when used improperly, it can add needless complexity. We'll look at frequent errors, useful MediatR patterns, and when it makes sense to utilize it in this post.
What Is MediatR?
MediatR is an in-process messaging library that enables communication between different parts of an application without creating direct dependencies.
Instead of a controller calling a service directly:
Controller
│
ProductService
│
Repository
The request flows through MediatR:
Controller
│
MediatR
│
Request Handler
│
Repository
The controller only knows about MediatR, while the business logic resides inside dedicated request handlers.
Request and Response Pattern
The most common MediatR pattern is the Request/Response model.
First, define a request:
using MediatR;
public record GetProductQuery(int Id) : IRequest<Product>;
Next, implement the handler:
public class GetProductHandler
: IRequestHandler<GetProductQuery, Product>
{
private readonly IProductRepository _repository;
public GetProductHandler(IProductRepository repository)
{
_repository = repository;
}
public async Task<Product> Handle(
GetProductQuery request,
CancellationToken cancellationToken)
{
return await _repository.GetByIdAsync(request.Id);
}
}
Finally, send the request from a controller:
[HttpGet("{id}")]
public async Task<IActionResult> Get(
int id,
IMediator mediator)
{
var product = await mediator.Send(new GetProductQuery(id));
return product is null
? NotFound()
: Ok(product);
}
This approach keeps controllers thin and delegates business logic to handlers.
Using Commands for Data Modification
Queries retrieve data, while commands modify it.
Example command:
public record CreateProductCommand(
string Name,
decimal Price) : IRequest<int>;
The corresponding handler performs validation, business logic, and persistence before returning the new product ID.
Separating commands and queries improves readability and aligns well with the Command Query Responsibility Segregation (CQRS) pattern.
Notifications for Multiple Actions
Sometimes a single event should trigger multiple independent actions.
For example:
- Send an email
- Update inventory
- Write an audit log
- Publish an integration event
Instead of placing all logic inside one handler, use notifications.
public record ProductCreatedNotification(int ProductId)
: INotification;
Each notification handler executes independently, making the application easier to extend without modifying existing code.
Pipeline Behaviors
One of MediatR's most powerful features is Pipeline Behaviors.
They allow cross-cutting concerns to execute before or after request handlers.
Common uses include:
- Validation
- Logging
- Performance monitoring
- Authorization
- Exception handling
Instead of duplicating logic across handlers, pipeline behaviors centralize these concerns, resulting in cleaner and more maintainable code.
When MediatR Works Best
MediatR provides the greatest value in applications that have:
- Complex business workflows
- Multiple use cases
- Clean Architecture
- CQRS implementation
- Large development teams
- Extensive testing requirements
For these applications, separating requests into dedicated handlers improves maintainability and reduces coupling.
When MediatR May Be Unnecessary
Not every application benefits from MediatR.
For a simple CRUD API with only a few endpoints, adding requests, handlers, and pipeline behaviors may increase complexity without delivering significant value.
A straightforward service layer is often sufficient for:
- Small internal tools
- Prototype applications
- Basic CRUD services
- Lightweight APIs
Choose MediatR when it solves an architectural problem—not simply because it's popular.
Common Mistakes
Creating a Handler for Every Tiny Operation
Some developers create handlers for trivial methods that simply forward calls to a repository.
For example:
Controller
│
Handler
│
Service
│
Repository
If the handler contains no business logic, MediatR adds an extra layer without improving maintainability.
Putting Business Logic in Controllers
Even when using MediatR, controllers should remain lightweight.
Avoid:
- Validation logic
- Business rules
- Database access
Controllers should receive requests, send them through MediatR, and return responses.
Overusing Notifications
Notifications are excellent for independent actions, but they should not be used when execution order or transactional consistency is critical.
If one operation depends on another, a command handler is usually a better choice.
Ignoring Pipeline Behaviors
Many teams adopt MediatR but continue duplicating validation and logging inside handlers.
Pipeline behaviors provide a cleaner and more reusable solution for cross-cutting concerns.
Best Practices
Keep handlers focused on a single responsibility.
Use commands for writes and queries for reads.
- Keep controllers thin.
- Use pipeline behaviors for validation, logging, and exception handling.
- Inject only the dependencies required by each handler.
- Avoid creating handlers that simply wrap repository methods.
- Group requests by feature to improve project organization.
- Unit test handlers independently from controllers.
HostForLIFE.eu ASP.NET Core 10.0 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.
