Post

Introduction to MediaTr

As your application grows, you may notice that your code becomes harder to maintain, especially when components tightly depend on each other. This is where MediatR comes in, helping you decouple complex logic by promoting the mediator pattern, which leads to more maintainable, scalable, and testable code.

MediatR is a simple and efficient .NET library that implements the mediator pattern, allowing you to dispatch commands, queries, and events between different parts of your application without them knowing about each other directly.

Advantages of MediaTr

  • Loose Coupling: MediatR promotes loose coupling by allowing different components to communicate through a mediator, without knowing the internal structure of the other components.
  • Separation of Concerns: By using MediatR, you separate the logic of dispatching commands, queries, or events from your main logic, making it easier to manage and maintain.
  • Scalability: As your application grows, adding new handlers for commands or queries becomes easier because each handler is separate and handles only one responsibility.
  • Testability: It’s easier to test specific parts of your application since handlers are isolated from each other. Mocking and unit testing become straightforward.
  • Cleaner Code: It helps keep your code organized, reducing the clutter of service injection in controller constructors or classes.

Examples of Usage

1. Install the nuget package

To begin using MediatR, install it via NuGet. Open your project, right-click -> Manage NuGet Packages, search for MediatR, and click Install. You’ll also want to install MediatR.Extensions.Microsoft.DependencyInjection for easy registration with the .NET Dependency Injection system. Install MediaTr

2. Define a Request and Handler

You’ll define a request by implementing either IRequest for queries and commands or INotification for events. Then, create a handler by implementing IRequestHandler<TRequest, TResponse>.

1
2
3
4
5
public class CreateUserRequest : IRequest<User>
{
    public string Name { get; set; }
    public string Email { get; set; }
}
1
2
3
4
5
6
7
8
public class CreateUserRequestHandler : IRequestHandler<CreateUserRequest, User>
{
    public async Task<User> Handle(CreateUserRequest request)
    {
        // ....................Create user logic
        return user;
    }
}

3. Register MediatR in Program.cs

To register MediatR, include it in your Program.cs file using the extension method provided by MediatR.Extensions.Microsoft.DependencyInjection.

1
builder.Services.AddMediatR(typeof(Program).Assembly);

4. Using MediatR in a Controller/Minimal API Endpoint

Now, you can inject IMediator into your controllers or services to handle requests, events, commands or queries:
Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IMediator _mediator;

    public UsersController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest request)
    {
        var user = await _mediator.Send(request);
        return CreatedAtAction(nameof(CreateUser), new { id = user.Id }, user);
    }
}

Minimal API:

1
2
3
4
5
6
7
app.MapPost("/api/users", async (IMediator mediator, CreateUserRequest request) =>
{
    var user = await mediator.Send(request);
    return Results.Created($"/api/users/{user.Id}", user);
})
.WithName("CreateUser")
.WithOpenApi();

The "magic" happens when you use the _mediator.Send(request) method. It sends the request, and the appropriate handlers registered for the type of object you are sending will process it.

5. Using Notifications/Events (Optional)

MediatR also supports notifications for broadcasting events. You define an event with the INotification interface and handle it using INotificationHandler.

1
2
3
4
public class UserCreatedNotification : INotification
{
    public User User { get; set; }
}
1
2
3
4
5
6
7
8
9
public class UserCreatedNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    public Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
    {
        // Logic to handle the event (e.g., logging, sending emails, etc.)
        Console.WriteLine($"User created: {notification.User.Name}");
        return Task.CompletedTask;
    }
}

Conclusion

MediatR simplifies the architecture of your application by promoting loose coupling and separation of concerns. With MediatR, you can better manage your commands, queries, and events, making your code more maintainable and easier to test. Start organizing your project today with MediatR and take full advantage of this powerful tool!

This post is licensed under CC BY 4.0 by the author.