ATCMediator Logo

Controla tus comandos y queries como una torre de control

ATCMediator es una implementación del patrón Mediator para arquitecturas limpias. Funciona como una “torre de control” para tus casos de uso o servicios, centralizando comandos y queries. La librería busca fomentar una comunidad para fortalecer la experiencia de desarrollo en C# .NET.

Ver en NuGet

Características

✅ Patrón Mediator limpio y eficiente
🧩 Integración sencilla con .NET
🔄 Soporte para comandos, queries
🛠️ Flexible para CQRS y arquitectura por capas
🚀 Rendimiento optimizado sin reflección costosa
📦 Compatible con .NET 8 en adelante
🧩 Soporte para behaviors tipo middleware

🚀 Instalación

Puedes instalar ATCMediator desde NuGet ejecutando:

dotnet add package ATCMediator --version 4.1.2

🔧 Registro en Program.cs

Después de instalar el paquete, registra los handlers en el contenedor de dependencias:


public static class DependencyInjection
{
    public static IServiceCollection AddMicroProductApplication(this IServiceCollection services)
    {
        // Registra todos los handlers de ATCMediator que estén en este ensamblado
        services.AddATCMediator(Assembly.GetExecutingAssembly());
        return services;
    }
}

Ejemplo completo

✅ Comando de entrada


public class CreateProductCommand : IAtcRequest
{
    public string? Name { get; set; }
    public decimal Price { get; set; }
}

💡 Handler del comando


public class CreateProductCommandHandler : IAtcRequestHandler  
{
    private readonly IProductRepository _productRepository;

    public CreateProductCommandHandler(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public async Task HandlerAsync(CreateProductCommand command, CancellationToken cancellationToken = default)
    {
        var product = Domain.Product.Product.Create(command.Name!, command.Price);
        await _productRepository.AddAsync(product);
        return product.Id;
    }
}

🔍 Consulta de productos


public class GetProductAllQuery : IAtcRequest> {}

📦 Handler de la consulta


public class GetProductAllQueryHandler : IAtcRequestHandler>
{
    private readonly IProductRepository _productRepository;

    public GetProductAllQueryHandler(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public async Task> HandlerAsync(GetProductAllQuery query, CancellationToken cancellationToken = default)
    {
        var products = await _productRepository.GetAllAsync();
        return products;
    }
}

🌐 Uso en un controlador ASP.NET Core


[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
    private readonly IMediator _mediator;

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

    [HttpPost]
    public async Task CrearProducto([FromBody] CreateProductCommand createProduct)
    {
        var result = await _mediator.ExecuteAsync(createProduct);
        return Ok(result);
    }

    [HttpGet]
    public async Task ObtenerProductos()
    {
        var productos = await _mediator.ExecuteAsync(new GetProductAllQuery());
        return Ok(productos);
    }
}

🧩 Agregar Behaviors personalizados

Puedes interceptar y extender el flujo de ejecución mediante la interfaz IAtcPipelineBehavior<TRequest, TResponse>. Esto permite aplicar validaciones, logs, autorización y más, al estilo de un middleware.

✨ Ejemplo: ValidationBehavior con FluentValidation

public class ValidationBehavior<TRequest, TResponse> : IAtcPipelineBehavior<TRequest, TResponse>
      where TRequest : IAtcRequest<TResponse>
  {
      private readonly IEnumerable<IValidator<TRequest>> _validators;
  
      public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
      {
          _validators = validators;
      }
  
      public async Task<TResponse> HandleAsync(
          TRequest request,
          CancellationToken cancellationToken,
          Func<Task<TResponse>> next)
      {
          var context = new ValidationContext<TRequest>(request);
          var failures = (await Task.WhenAll(
              _validators.Select(v => v.ValidateAsync(context, cancellationToken))))
              .SelectMany(r => r.Errors)
              .Where(f => f != null)
              .ToList();
  
          if (failures.Any())
              throw new ValidationException(failures);
  
          return await next();
      }
  }

🧪 Registro del Behavior y Validadores

builder.Services.AddScoped(typeof(IAtcPipelineBehavior<,>), typeof(ValidationBehavior<,>));
  builder.Services.AddValidatorsFromAssemblyContaining<CreateProductValidator>();

Puedes encadenar múltiples behaviors para crear un pipeline robusto y flexible:

🛡️ Middleware para capturar excepciones de validación

public class ValidationExceptionMiddleware
  {
      private readonly RequestDelegate _next;
  
      public ValidationExceptionMiddleware(RequestDelegate next)
      {
          _next = next;
      }
  
      public async Task Invoke(HttpContext context)
      {
          try
          {
              await _next(context);
          }
          catch (ValidationException ex)
          {
              context.Response.StatusCode = StatusCodes.Status400BadRequest;
              context.Response.ContentType = "application/json";
  
              var errors = ex.Errors
                  .Select(f => new { f.PropertyName, f.ErrorMessage })
                  .ToList();
  
              await context.Response.WriteAsJsonAsync(new
              {
                  message = "La validación falló.",
                  errors
              });
          }
      }
  }

Y lo registras en Program.cs antes del controlador:

app.UseMiddleware<ValidationExceptionMiddleware>();