🚀 Quick Guide: MediatR in .NET 8

Konstantin Fedorov
3 min readMay 10, 2024

Hello coder! If you are tired of complex code and want to make things easier, I have good news for you. MediatR is a great tool that creates a special pattern called a mediator. It makes lots of tasks automatic, allowing machines to communicate with each other and achieve great results.

Introduction

MediatR makes it easy to use the mediator design pattern in your apps. It acts like a middleman, ensuring that commands, queries, and notifications are managed well without any confusion. In CQRS, MediatR excels by keeping read and write tasks apart, making your code neater and easier to grow.

Setting Up MediatR

First things first, let’s get MediatR into your project:

dotnet add package MediatR.Extensions.Microsoft.DependencyInjection

Now, let’s wire it up in your Startup.cs or Program.cs

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMediatR(typeof(Startup));
}
}

CQRS with MediatR — Let’s Do This!

Command Example

Commands are your go-to for making changes in the system. Let’s take a look at a simple CreateOrderCommand

public record CreateOrderCommand(string ProductName, int Quantity) : IRequest<OrderResponse>;

public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, OrderResponse>
{
public Task<OrderResponse> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
return Task.FromResult(new OrderResponse { Success = true });
}
}

Query Example

Queries are all about retrieving data without modifying anything. Here’s an example of GetOrderByIdQuery:

public record GetOrderByIdQuery(int OrderId) : IRequest<Order>;

public class GetOrderByIdHandler : IRequestHandler<GetOrderByIdQuery, Order>
{
public Task<Order> Handle(GetOrderByIdQuery request, CancellationToken cancellationToken)
{
return Task.FromResult(new Order { Id = request.OrderId, ProductName = "Sample Product" });
}
}

Making Pipelines

Mediator pipelines allow you to add useful features such as logging, validation, and caching, without disrupting your main logic.

Behaviors allow you to wrap your request-handling logic in additional features.

Logging Behavior

Would you like to log every request? Here’s how:

public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;

public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}

public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
_logger.LogInformation($"Handling {typeof(TRequest).Name}");
var response = await next();
_logger.LogInformation($"Handled {typeof(TResponse).Name}");
return response;
}
}

Cache Behavior

Speed things up with caching:

public class CacheBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
private readonly IMemoryCache _cache;
private readonly ILogger<CacheBehavior<TRequest, TResponse>> _logger;

public CacheBehavior(IMemoryCache cache, ILogger<CacheBehavior<TRequest, TResponse>> logger)
{
_cache = cache;
_logger = logger;
}

public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
var cacheKey = request.GetHashCode().ToString();

if (_cache.TryGetValue(cacheKey, out TResponse response))
{
_logger.LogInformation($"Returning cached response for {typeof(TRequest).Name}");
return response;
}

_logger.LogInformation($"Cache miss for {typeof(TRequest).Name}. Invoking handler.");
response = await next();

_cache.Set(cacheKey, response, TimeSpan.FromMinutes(5));

return response;
}
}

Registration

To control the order in which mediator pipelines are executed in MediatR, you can register the behaviors in the desired order in the startup configuration of your application.

services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(ServicesExtensions).Assembly));

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CacheBehavior<,>));

Conclusion

The MediatR in .NET 8 is great for CQRS. It has neat pipeline features. You can add logging, checking, caching, and more. This keeps your code clean and sturdy. Whether you’re working with actions, requests, or alerts, the Mediator makes life simple. This lets you concentrate on your business rules without stressing about the technical parts.

👏 If you find this content helpful, I’d appreciate it if you could give it a clap (you can clap more than once by holding down the button). Also, I’m encouraging you to leave your thoughts and suggestions in the comments so we can continue to discuss this topic.

Thanks for reading…

--

--