Workshop : SOLID avec MediatR pour microservices

Découvrez comment appliquer les principes SOLID et le pattern MediatR pour concevoir des microservices maintenables et évolutifs. Un guide pratique pour améliorer la qualité de votre code et facili...

Olivier Dupuy
05 août 2025

6

Vues

0

Commentaires

2

Min de lecture

Dans le monde du développement .NET moderne, la création de microservices robustes et maintenables nécessite l'application rigoureuse des principes SOLID combinée à des patterns efficaces. Ce workshop explore l'utilisation de MediatR, une bibliothèque puissante qui facilite l'implémentation du pattern Mediator, en conjonction avec les principes SOLID pour construire des microservices élégants et évolutifs.

Les fondamentaux : SOLID et MediatR

Les principes SOLID constituent la base d'une architecture logicielle saine :

  • Single Responsibility Principle (SRP)
  • Open/Closed Principle (OCP)
  • Liskov Substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)

MediatR implémente le pattern Mediator, permettant de découpler les composants et de centraliser la gestion des requêtes/réponses.

Mise en place du projet


// Installation des packages NuGet nécessaires
dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection

Configuration de base


public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Enregistrement de MediatR
        services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Startup).Assembly));
        
        // Configuration des autres services
        services.AddControllers();
    }
}

Implémentation des Handlers et Commands


// Command
public class CreateOrderCommand : IRequest
{
    public string CustomerId { get; set; }
    public List Items { get; set; }
}

// Handler public class CreateOrderHandler : IRequestHandler { private readonly IOrderRepository _orderRepository; public CreateOrderHandler(IOrderRepository orderRepository) { _orderRepository = orderRepository; } public async Task Handle( CreateOrderCommand request, CancellationToken cancellationToken) { // Logique métier var order = new Order { CustomerId = request.CustomerId, Items = request.Items }; await _orderRepository.CreateAsync(order, cancellationToken); return new OrderResult { OrderId = order.Id }; } }

Intégration dans les Controllers


[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IMediator _mediator;
    
    public OrdersController(IMediator mediator)
    {
        _mediator = mediator;
    }
    
    [HttpPost]
    public async Task> CreateOrder(
        CreateOrderCommand command)
    {
        var result = await _mediator.Send(command);
        return Ok(result);
    }
}

Pipeline Behaviors

Les Pipeline Behaviors permettent d'implémenter des aspects transversaux comme la validation ou la journalisation.


public class LoggingBehavior 
    : IPipelineBehavior
{
    private readonly ILogger> _logger;
    
    public LoggingBehavior(
        ILogger> logger)
    {
        _logger = logger;
    }
    
    public async Task Handle(
        TRequest request,
        RequestHandlerDelegate next,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Handling {typeof(TRequest).Name}");
        var response = await next();
        _logger.LogInformation($"Handled {typeof(TRequest).Name}");
        return response;
    }
}

Validation avec FluentValidation


public class CreateOrderCommandValidator 
    : AbstractValidator
{
    public CreateOrderCommandValidator()
    {
        RuleFor(x => x.CustomerId)
            .NotEmpty()
            .MaximumLength(50);
            
        RuleFor(x => x.Items)
            .NotEmpty()
            .Must(items => items.Count <= 100)
            .WithMessage("Order cannot contain more than 100 items");
    }
}

Tests unitaires


public class CreateOrderHandlerTests
{
    private readonly Mock _orderRepositoryMock;
    private readonly CreateOrderHandler _handler;
    
    public CreateOrderHandlerTests()
    {
        _orderRepositoryMock = new Mock();
        _handler = new CreateOrderHandler(_orderRepositoryMock.Object);
    }
    
    [Fact]
    public async Task Handle_ValidCommand_CreatesOrder()
    {
        // Arrange
        var command = new CreateOrderCommand
        {
            CustomerId = "123",
            Items = new List()
        };
        
        // Act
        var result = await _handler.Handle(
            command, 
            CancellationToken.None);
            
        // Assert
        Assert.NotNull(result);
        _orderRepositoryMock.Verify(
            x => x.CreateAsync(
                It.IsAny(), 
                It.IsAny()), 
            Times.Once);
    }
}

Bonnes pratiques et recommandations

  • Gardez les Commands et Queries séparés (CQRS)
  • Utilisez des DTOs pour la communication entre les couches
  • Implémentez la validation au niveau des Commands
  • Utilisez des Pipeline Behaviors pour la logique transversale
  • Testez les Handlers de manière isolée

Considérations de performance

Pour optimiser les performances :

  • Utilisez le pooling d'objets pour les requêtes fréquentes
  • Implémentez le caching approprié
  • Évitez les opérations bloquantes dans les Handlers
  • Utilisez des types de retour asynchrones

Conclusion

L'utilisation combinée de SOLID et MediatR offre une base solide pour construire des microservices maintenables et évolutifs. Cette approche favorise :

  • Une séparation claire des responsabilités
  • Une meilleure testabilité
  • Une maintenance simplifiée
  • Une évolutivité accrue

En suivant ces patterns et pratiques, vous pouvez construire des applications .NET robustes et professionnelles qui résisteront à l'épreuve du temps.

Partager cet article
42
12

Commentaires (0)

Rejoignez la discussion

Connectez-vous pour partager votre avis et échanger avec la communauté

Première discussion

Soyez le premier à partager votre avis sur cet article !

À propos de l'auteur
Olivier Dupuy

Développeur passionné et contributeur actif de la communauté technique.

Profil
Navigation rapide
Commentaires (0)