一键导入
mediatr-handlers
Use when implementing MediatR request handlers, notification handlers, or command/query dispatch.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when implementing MediatR request handlers, notification handlers, or command/query dispatch.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when adding caching to .NET APIs or optimizing response times with distributed cache, output cache, or ETags.
Use when configuring API response formats, custom formatters, or Accept header handling.
Use when building controller-based REST APIs with action results, model binding, or MediatR integration.
Use when creating RESTful API controllers with MediatR dispatch and ProblemDetails error responses.
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when building minimal API endpoints with route groups, filters, or TypedResults.
| name | mediatr-handlers |
| description | Use when implementing MediatR request handlers, notification handlers, or command/query dispatch. |
| metadata | {"category":"cqrs","agent":"ef-specialist","when-to-use":"When creating or modifying MediatR request handlers or notification handlers"} |
IRequest<TResponse> for operations that change stateIRequest<TResponse> for read-only data retrievalINotification for one-to-many event dispatchRegisterServicesFromAssembly// Command record — immutable, represents intent
public sealed record CreateOrderCommand(
string CustomerName,
List<CreateOrderCommand.ItemDto> Items) : IRequest<Result<Guid>>
{
public sealed record ItemDto(Guid ProductId, int Quantity);
}
// Handler — internal, one per command
internal sealed class CreateOrderCommandHandler(
IOrderRepository repository,
IUnitOfWork unitOfWork,
ILogger<CreateOrderCommandHandler> logger)
: IRequestHandler<CreateOrderCommand, Result<Guid>>
{
public async Task<Result<Guid>> Handle(
CreateOrderCommand request, CancellationToken ct)
{
var order = Order.Create(request.CustomerName);
foreach (var item in request.Items)
order.AddItem(item.ProductId, item.Quantity);
repository.Add(order);
await unitOfWork.SaveChangesAsync(ct);
logger.LogInformation(
"Created order {OrderId} for {Customer}",
order.Id, request.CustomerName);
return Result<Guid>.Success(order.Id);
}
}
// Query record
public sealed record GetOrderQuery(Guid OrderId)
: IRequest<OrderResponse?>;
// Handler with DbContext (read-only, no repository needed)
internal sealed class GetOrderQueryHandler(AppDbContext db)
: IRequestHandler<GetOrderQuery, OrderResponse?>
{
public async Task<OrderResponse?> Handle(
GetOrderQuery request, CancellationToken ct)
{
return await db.Orders
.AsNoTracking()
.Where(o => o.Id == request.OrderId)
.Select(o => new OrderResponse(
o.Id,
o.CustomerName,
o.Total,
o.Status.ToString(),
o.CreatedAt,
o.Items.Select(i => new OrderItemResponse(
i.ProductId, i.ProductName,
i.Quantity, i.UnitPrice)).ToList()))
.FirstOrDefaultAsync(ct);
}
}
// IRequest with no generic parameter = Unit return
public sealed record DeleteOrderCommand(Guid OrderId) : IRequest;
internal sealed class DeleteOrderCommandHandler(
IOrderRepository repository,
IUnitOfWork unitOfWork)
: IRequestHandler<DeleteOrderCommand>
{
public async Task Handle(
DeleteOrderCommand request, CancellationToken ct)
{
var order = await repository.FindAsync(request.OrderId, ct)
?? throw new NotFoundException("Order", request.OrderId);
repository.Remove(order);
await unitOfWork.SaveChangesAsync(ct);
}
}
// Notification — dispatched to multiple handlers
public sealed record OrderCreatedNotification(
Guid OrderId,
string CustomerName) : INotification;
// Handler 1: send email
internal sealed class SendOrderConfirmationEmail(
IEmailService emailService)
: INotificationHandler<OrderCreatedNotification>
{
public async Task Handle(
OrderCreatedNotification notification,
CancellationToken ct)
{
await emailService.SendOrderConfirmationAsync(
notification.OrderId, notification.CustomerName, ct);
}
}
// Handler 2: update analytics
internal sealed class UpdateOrderAnalytics(AppDbContext db)
: INotificationHandler<OrderCreatedNotification>
{
public async Task Handle(
OrderCreatedNotification notification,
CancellationToken ct)
{
var stats = await db.DashboardStats.SingleAsync(ct);
stats.IncrementOrderCount();
await db.SaveChangesAsync(ct);
}
}
// Program.cs — register all handlers from assembly
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
// Or from multiple assemblies
cfg.RegisterServicesFromAssemblies(
typeof(CreateOrderCommand).Assembly,
typeof(OrderCreatedNotification).Assembly);
});
// ISender for commands and queries
app.MapPost("/orders", async (
CreateOrderCommand cmd,
ISender sender,
CancellationToken ct) =>
{
var result = await sender.Send(cmd, ct);
return result.Match(
id => Results.Created($"/orders/{id}", new { id }),
error => Results.BadRequest(error.ToProblemDetails()));
});
// IPublisher for notifications
app.MapPost("/orders/{id}/submit", async (
Guid id, ISender sender, IPublisher publisher,
CancellationToken ct) =>
{
await sender.Send(new SubmitOrderCommand(id), ct);
await publisher.Publish(
new OrderSubmittedNotification(id), ct);
return Results.NoContent();
});
| Type | Pattern | Example |
|---|---|---|
| Command | {Verb}{Noun}Command | CreateOrderCommand |
| Query | Get{Noun}Query / List{Noun}Query | GetOrderQuery |
| Handler | {Command/Query}Handler | CreateOrderCommandHandler |
| Notification | {Noun}{PastVerb}Notification | OrderCreatedNotification |
| Validator | {Command}Validator | CreateOrderCommandValidator |
internal sealed)IRequest< and IRequestHandler< implementationsINotification and INotificationHandler< implementationsMediatR package reference in .csprojISender or IMediator injectionRegisterServicesFromAssembly callsdotnet add package MediatRAddMediatR in Program.csISender.Send