Skip to main content

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);
});