CQRS with MediatR
Setup
dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
Commands
// Command
public record CreateProductCommand(string Name, decimal Price) : IRequest<int>;
// Handler
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, int>
{
private readonly IApplicationDbContext _context;
public async Task<int> Handle(CreateProductCommand request, CancellationToken ct)
{
var product = new Product(request.Name, request.Price);
_context.Products.Add(product);
await _context.SaveChangesAsync(ct);
return product.Id;
}
}
Queries
// Query
public record GetProductByIdQuery(int Id) : IRequest<ProductDto>;
// Handler
public class GetProductByIdQueryHandler : IRequestHandler<GetProductByIdQuery, ProductDto>
{
public async Task<ProductDto> Handle(GetProductByIdQuery request, CancellationToken ct)
{
return await _context.Products
.Where(p => p.Id == request.Id)
.Select(p => new ProductDto(p.Id, p.Name, p.Price))
.FirstOrDefaultAsync(ct);
}
}
Usage in Endpoint
app.MapPost("/api/products", async (CreateProductCommand command, IMediator mediator) =>
{
var id = await mediator.Send(command);
return Results.Created($"/api/products/{id}", new { id });
});
app.MapGet("/api/products/{id}", async (int id, IMediator mediator) =>
{
var product = await mediator.Send(new GetProductByIdQuery(id));
return product is null ? Results.NotFound() : Results.Ok(product);
});