一键导入
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 页面并帮你完成安装。
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when writing async code, propagating CancellationTokens, or fixing async/await pitfalls.
Use when applying or enforcing C# coding style — namespaces, sealed classes, var usage, XML docs.
Use when applying modern C# idioms — records, pattern matching, primary constructors, collection expressions.
Use when registering services, choosing lifetimes, or implementing DI patterns like decorator or keyed services.
Use when selecting or implementing design patterns in C# — factory, builder, strategy, decorator, or mediator.
基于 SOC 职业分类
| 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