MediatR query handlers using IUnitOfWork with named repository properties. Repositories encapsulate filtering, pagination, and sorting. Single-entity queries use FindAsync with DTO mapping. List queries delegate to repository methods returning output DTOs. Trigger: query handler, pagination, filtering, read operations.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
IRequestHandler<TQuery, TOutput> via MediatR_unitOfWork.Orders)PageSize, CurrentPage, Total, and collection propertiesFindAsync then map to output DTOOrderNotFoundException)namespace {Company}.{Domain}.Query.Application.Contracts.Repositories;
public interface IUnitOfWork : IDisposable
{
IOrderRepository Orders { get; }
IProductRepository Products { get; }
IOrderItemRepository OrderItems { get; }
ICategoryRepository Categories { get; }
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}
namespace {Company}.{Domain}.Query.Application.Contracts.Repositories;
public interface IAsyncRepository<TDomain> where TDomain : class
{
Task AddAsync(TDomain entity);
Task AddRangeAsync(IEnumerable<TDomain> entities);
Task RemoveAsync(TDomain entity);
Task RemoveRangeAsync(IEnumerable<TDomain> entities);
Task<TDomain?> FindAsync(Guid id, bool includeRelated = false);
Task<IEnumerable<TDomain>> GetAllAsync();
Task<IEnumerable<TResult>> GetAllAsync<TResult>(
Expression<Func<TDomain, TResult>> target);
IQueryable<TDomain> GetQueryable();
}
namespace {Company}.{Domain}.Query.Application.Contracts.Repositories;
public interface IOrderRepository : IAsyncRepository<Order>
{
Task<GetOrdersOutput> GetOrdersAsync(
GetOrdersQuery query,
CancellationToken cancellationToken);
}
namespace {Company}.{Domain}.Query.Application.Features.Queries;
public record GetOrdersQuery(
int PageSize,
int CurrentPage,
DateTime? CreatedFrom,
DateTime? CreatedTo,
OrderStatus? Status,
string? CustomerName
) : IRequest<GetOrdersOutput>;
namespace {Company}.{Domain}.Query.Application.Features.Queries;
public class GetOrdersOutput
{
public int PageSize { get; set; }
public int CurrentPage { get; set; }
public int Total { get; set; }
public List<OrderOutput> Orders { get; set; } = [];
}
namespace {Company}.{Domain}.Query.Application.Features.Queries;
public class OrderOutput
{
public Guid Id { get; set; }
public string CustomerName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public decimal Total { get; set; }
public OrderStatus Status { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
}
namespace {Company}.{Domain}.Query.Application.Features.Queries;
public class GetOrdersHandler(IUnitOfWork unitOfWork)
: IRequestHandler<GetOrdersQuery, GetOrdersOutput>
{
private readonly IUnitOfWork _unitOfWork = unitOfWork;
public async Task<GetOrdersOutput> Handle(
GetOrdersQuery query,
CancellationToken cancellationToken)
{
return await _unitOfWork.Orders
.GetOrdersAsync(query, cancellationToken);
}
}
namespace {Company}.{Domain}.Query.Application.Features.Queries;
public record GetOrderByIdQuery(Guid Id) : IRequest<OrderOutput>;
public class GetOrderByIdHandler(IUnitOfWork unitOfWork)
: IRequestHandler<GetOrderByIdQuery, OrderOutput>
{
private readonly IUnitOfWork _unitOfWork = unitOfWork;
public async Task<OrderOutput> Handle(
GetOrderByIdQuery query,
CancellationToken cancellationToken)
{
var order = await _unitOfWork.Orders.FindAsync(query.Id)
?? throw new OrderNotFoundException();
return new OrderOutput
{
Id = order.Id,
CustomerName = order.CustomerName,
Email = order.Email,
Total = order.Total,
Status = order.Status,
IsActive = order.IsActive,
CreatedAt = order.CreatedAt
};
}
}
public class GetOrderDetailsHandler(
IUnitOfWork unitOfWork,
IQueriesService queriesService)
: IRequestHandler<GetOrderDetailsQuery, OrderDetailsOutput>
{
private readonly IUnitOfWork _unitOfWork = unitOfWork;
private readonly IQueriesService _queriesService = queriesService;
public async Task<OrderDetailsOutput> Handle(
GetOrderDetailsQuery query,
CancellationToken cancellationToken)
{
var order = await _unitOfWork.Orders.FindAsync(query.Id, true)
?? throw new OrderNotFoundException();
var extraInfo = await _queriesService
.GetAdditionalInfo(order.ExternalId);
return new OrderDetailsOutput { /* map fields */ };
}
}
| Query Type | Pattern | Returns |
|---|---|---|
| List with pagination | Delegate to repository method | GetOrdersOutput with Total, PageSize, CurrentPage |
| Single by ID | FindAsync + map to output | Output DTO or throw NotFoundException |
| Single by field | Repository-specific method | Output DTO or throw NotFoundException |
| With external data | Additional service injection | Combined output |
| Anti-Pattern | Correct Approach |
|---|---|
ApplicationDbContext injected directly | Use IUnitOfWork with named repositories |
Paginated<T> generic wrapper | Output class with PageSize, CurrentPage, Total, collection |
AsNoTracking() in handlers | Tracking handled at repository/infrastructure level |
| Filtering logic in handlers | Repository methods encapsulate all query logic |
| Returning entities from queries | Map to output DTOs in handler |
record output types | class output types with { get; set; } properties |
# Find query handlers
grep -r "IRequestHandler<.*Query" --include="*.cs" Application/Features/Queries/
# Find IUnitOfWork usage in queries
grep -r "_unitOfWork\." --include="*.cs" Application/Features/Queries/
# Find output classes
grep -r "public class.*Output" --include="*.cs" Application/Features/Queries/
# Find repository interfaces with query methods
grep -r "Task<Get.*Output>" --include="*.cs" Application/Contracts/
FindAsync then map to output DTO in handlerclass with PageSize, CurrentPage, Total, and collectionrecord type with filter parameters as nullableApplication/Features/Queries/{Area}/{QueryName}/ directory