بنقرة واحدة
net-cqrs
Implement CQRS pattern with MediatR for .NET applications
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Implement CQRS pattern with MediatR for .NET applications
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Implement agile development practices and ceremonies for .NET projects
Automate Work Item -> Branch -> PR -> Evidence Pack for AI Coding Factory
Implement Scrum framework and team structures for .NET enterprise projects
Create Docker configuration for ASP.NET Core applications
Create domain models following Domain-Driven Design principles
Create GitHub Actions CI/CD pipelines for .NET applications
| name | net-cqrs |
| description | Implement CQRS pattern with MediatR for .NET applications |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":".net-developers","framework":"aspnetcore","patterns":"cqrs, mediator, event-sourcing"} |
I help you implement CQRS (Command Query Responsibility Segregation):
Use this skill when:
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.0" />
using MediatR;
public interface ICommand<out TResult> : IRequest<TResult>
{
}
public interface ICommandHandler<in TCommand, TResult> : IRequestHandler<TCommand, TResult>
where TCommand : ICommand<TResult>
{
}
public record CreateOrderCommand(
Guid CustomerId,
List<OrderItemDto> Items,
string ShippingAddress
) : ICommand<OrderDto>;
public class CreateOrderCommandHandler : ICommandHandler<CreateOrderCommand, OrderDto>
{
private readonly IOrderRepository _orderRepository;
private readonly IMapper _mapper;
private readonly IPublisher _publisher;
public CreateOrderCommandHandler(
IOrderRepository orderRepository,
IMapper mapper,
IPublisher publisher)
{
_orderRepository = orderRepository;
_mapper = mapper;
_publisher = publisher;
}
public async Task<OrderDto> Handle(
CreateOrderCommand request,
CancellationToken cancellationToken)
{
var order = Order.Create(
request.CustomerId,
request.Items.Select(i => new OrderItem(i.ProductId, i.Quantity, i.Price)),
request.ShippingAddress);
await _orderRepository.AddAsync(order, cancellationToken);
// Publish domain events
foreach (var domainEvent in order.DomainEvents)
{
await _publisher.Publish(domainEvent, cancellationToken);
}
order.ClearDomainEvents();
return _mapper.Map<OrderDto>(order);
}
}
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
{
public CreateOrderCommandValidator()
{
RuleFor(x => x.CustomerId)
.NotEmpty()
.WithMessage("Customer ID is required");
RuleFor(x => x.Items)
.NotEmpty()
.WithMessage("At least one item is required");
RuleForEach(x => x.Items)
.ChildRules(item =>
{
item.RuleFor(x => x.Quantity)
.GreaterThan(0)
.WithMessage("Quantity must be greater than 0");
item.RuleFor(x => x.Price)
.GreaterThan(0)
.WithMessage("Price must be greater than 0");
});
RuleFor(x => x.ShippingAddress)
.NotEmpty()
.MaximumLength(500)
.WithMessage("Shipping address is required (max 500 characters)");
}
}
using MediatR;
public interface IQuery<out TResult> : IRequest<TResult>
{
}
public interface IQueryHandler<in TQuery, TResult> : IRequestHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
}
public record GetOrderByIdQuery(Guid OrderId) : IQuery<OrderDto?>;
public class GetOrderByIdQueryHandler : IQueryHandler<GetOrderByIdQuery, OrderDto?>
{
private readonly IOrderReadRepository _orderReadRepository;
private readonly IMapper _mapper;
public GetOrderByIdQueryHandler(
IOrderReadRepository orderReadRepository,
IMapper mapper)
{
_orderReadRepository = orderReadRepository;
_mapper = mapper;
}
public async Task<OrderDto?> Handle(
GetOrderByIdQuery request,
CancellationToken cancellationToken)
{
var order = await _orderReadRepository.GetByIdAsync(
request.OrderId,
cancellationToken);
return order is null ? null : _mapper.Map<OrderDto>(order);
}
}
public record GetOrdersQuery(
Guid? CustomerId,
DateTime? FromDate,
DateTime? ToDate,
int Page = 1,
int PageSize = 10
) : IQuery<PaginatedList<OrderSummaryDto>>;
public class GetOrdersQueryHandler : IQueryHandler<GetOrdersQuery, PaginatedList<OrderSummaryDto>>
{
private readonly IOrderReadRepository _repository;
public GetOrdersQueryHandler(IOrderReadRepository repository)
{
_repository = repository;
}
public async Task<PaginatedList<OrderSummaryDto>> Handle(
GetOrdersQuery request,
CancellationToken cancellationToken)
{
return await _repository.GetPaginatedAsync(
request.CustomerId,
request.FromDate,
request.ToDate,
request.Page,
request.PageSize,
cancellationToken);
}
}
public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
if (!_validators.Any())
return await next();
var context = new ValidationContext<TRequest>(request);
var validationResults = await Task.WhenAll(
_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.SelectMany(r => r.Errors)
.Where(f => f is not null)
.ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
return await next();
}
}
public class TransactionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : ICommand<TResponse>
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger<TransactionBehaviour<TRequest, TResponse>> _logger;
public TransactionBehaviour(
IUnitOfWork unitOfWork,
ILogger<TransactionBehaviour<TRequest, TResponse>> logger)
{
_unitOfWork = unitOfWork;
_logger = logger;
}
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
var typeName = typeof(TRequest).Name;
try
{
await _unitOfWork.BeginTransactionAsync(cancellationToken);
_logger.LogInformation("Begin transaction for {CommandName}", typeName);
var response = await next();
await _unitOfWork.CommitTransactionAsync(cancellationToken);
_logger.LogInformation("Committed transaction for {CommandName}", typeName);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during transaction for {CommandName}", typeName);
await _unitOfWork.RollbackTransactionAsync(cancellationToken);
throw;
}
}
}
public class OrderCreatedEventHandler : INotificationHandler<OrderCreatedEvent>
{
private readonly IEmailService _emailService;
private readonly ILogger<OrderCreatedEventHandler> _logger;
public OrderCreatedEventHandler(
IEmailService emailService,
ILogger<OrderCreatedEventHandler> logger)
{
_emailService = emailService;
_logger = logger;
}
public async Task Handle(
OrderCreatedEvent notification,
CancellationToken cancellationToken)
{
_logger.LogInformation(
"Processing OrderCreatedEvent for Order {OrderId}",
notification.OrderId);
await _emailService.SendOrderConfirmationAsync(
notification.OrderId,
notification.CustomerEmail,
cancellationToken);
}
}
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
// Add behaviors in order of execution
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(LoggingBehaviour<,>));
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>));
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionBehaviour<,>));
});
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
Use net-cqrs skill to:
1. Create command with handler and validator
2. Create query with pagination support
3. Set up MediatR pipeline behaviors
4. Implement domain event handlers
5. Configure transaction behavior for commands
I will generate complete CQRS implementation following Clean Architecture principles.