Pipeline behaviors are MediatR’s equivalent of middleware: each behavior wraps the next handler in the chain, forming an ordered pipeline that applies cross-cutting concerns — such as logging, validation, and transaction management — to every command or query without polluting individual handler implementations. SharedKernel provides eight purpose-built pipeline services and registers them automatically via two extension methods onDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/jordiaragonzaragoza/JordiAragonZaragoza.SharedKernel/llms.txt
Use this file to discover all available pages before exploring further.
IServiceCollection.
Registration
Call the appropriate extension method when configuring your service container. Both methods live inApplicationDependencyInjection:
AddSharedKernelApplicationCommandBus() registers all eight services (including RequestUnitOfWorkService).
AddSharedKernelApplicationQueryBus() registers seven services — everything except RequestUnitOfWorkService, because queries must never modify state.
services.AddMediatR(...)) and provide concrete implementations of IUnitOfWork, ICacheService, IIdentityService, and IUserContextService in your infrastructure layer.Pipeline Services
1. RequestLoggerService — structured request logging
1. RequestLoggerService — structured request logging
IRequestLoggerServiceClass:
RequestLoggerServiceLogs every incoming request at Debug level before it reaches the handler. The log entry includes the request type name, the current user ID (from IUserContextService), and the serialized request body. If the request implements ISanitizableRequest, the sanitized representation is serialized instead of the raw object.2. RequestExceptionHandlerService — unhandled exception safety net
2. RequestExceptionHandlerService — unhandled exception safety net
IRequestExceptionHandlerServiceClass:
RequestExceptionHandlerServiceWraps the rest of the pipeline in a try/catch. On any unhandled exception it logs at Error level — including the request name, user ID, and sanitized request data — and then re-throws, letting the presentation layer’s exception middleware decide on the HTTP status code.3. RequestValidationService — FluentValidation integration
3. RequestValidationService — FluentValidation integration
IRequestValidationService<TRequest, TResponse>Class:
RequestValidationService<TRequest, TResponse>Resolves all registered IValidator<TRequest> implementations from the DI container and runs them concurrently. If any validators produce failures, the service returns Result.Invalid(errors) (or Result<T>.Invalid(errors)) immediately — the handler is never invoked. Validation failures are logged at Information level with the full list of broken rules.services.AddValidatorsFromAssembly(...).4. RequestAuthorizationService — attribute-driven authorization
4. RequestAuthorizationService — attribute-driven authorization
5. RequestCachingService — response caching
5. RequestCachingService — response caching
IRequestCachingServiceClass:
RequestCachingServiceActivated only for requests that implement ICacheRequest. On the first call the handler executes and the result is stored in ICacheService. Subsequent calls with the same cache key return the cached value directly, bypassing the handler entirely.ICacheRequest contract:6. RequestInvalidateCachingService — cache invalidation
6. RequestInvalidateCachingService — cache invalidation
IRequestInvalidateCachingServiceClass:
RequestInvalidateCachingServiceActivated only for requests that implement IInvalidateCacheRequest. After the handler runs successfully, all cache entries whose key starts with the given prefix are removed via ICacheService.RemoveByPrefixAsync.IInvalidateCacheRequest contract:7. RequestUnitOfWorkService — transactional command execution
7. RequestUnitOfWorkService — transactional command execution
IRequestUnitOfWorkServiceClass:
RequestUnitOfWorkServiceWraps command handlers that implement ITransactionalCommand (i.e., those using ICommand or ICommand<TResponse>) in a database transaction via IUnitOfWork.ExecuteInTransactionAsync. The service also translates two domain exceptions into typed Result values so they never surface as HTTP 500 errors:NotFoundException→Result.NotFound(...)BusinessRuleValidationException→Result.Invalid(...)
IUnitOfWork interface it delegates to:RequestUnitOfWorkService is not registered by AddSharedKernelApplicationQueryBus(). Queries are always non-transactional.8. RequestPerformanceTrackingService — slow-request detection
8. RequestPerformanceTrackingService — slow-request detection
IRequestPerformanceTrackingServiceClass:
RequestPerformanceTrackingServiceTimes every request with a Stopwatch. After the handler completes it logs at Debug level with elapsed milliseconds, request name, user ID, and both the sanitized request and response values. If execution exceeds 1 500 ms it additionally logs a Warning so slow endpoints are immediately visible in your observability tooling.Command Pipeline Execution Order
The behaviors are composed by the infrastructure layer’s MediatR registration. The intended execution order for a transactional command is:RequestExceptionHandlerService
try/catch around the remaining pipeline. Logs and re-throws on any unhandled exception.RequestValidationService
IValidator<TCommand> implementations. Returns Result.Invalid immediately if any rule fails.RequestAuthorizationService
[Authorize] attributes on the command class. Returns Result.Unauthorized or Result.Forbidden if the check fails.RequestCachingService
ICacheRequest, attempts a cache read and short-circuits on a hit.RequestInvalidateCachingService
IInvalidateCacheRequest, executes the handler and then removes the cache prefix on success.RequestUnitOfWorkService
NotFoundException and BusinessRuleValidationException into typed Result values.Using ISanitizableRequest with Pipelines
All pipeline services that serialize request data to logs (RequestLoggerService, RequestValidationService, RequestExceptionHandlerService, RequestPerformanceTrackingService) check whether the request implements ISanitizableRequest. If it does, they call GetSanitized() and serialize that object instead: