بنقرة واحدة
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 المهني
| 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.SendUse 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.