IronAlpine.Mediator
3.0.0
dotnet add package IronAlpine.Mediator --version 3.0.0
NuGet\Install-Package IronAlpine.Mediator -Version 3.0.0
<PackageReference Include="IronAlpine.Mediator" Version="3.0.0" />
<PackageVersion Include="IronAlpine.Mediator" Version="3.0.0" />
<PackageReference Include="IronAlpine.Mediator" />
paket add IronAlpine.Mediator --version 3.0.0
#r "nuget: IronAlpine.Mediator, 3.0.0"
#:package IronAlpine.Mediator@3.0.0
#addin nuget:?package=IronAlpine.Mediator&version=3.0.0
#tool nuget:?package=IronAlpine.Mediator&version=3.0.0
IronAlpine.Mediator
Request/response orchestration with validation, caching, and behavior pipeline.
- Target Frameworks: net9.0, net10.0
- Dependencies: FluentValidation, Microsoft.Extensions.DependencyInjection
- Package Size: ~120 KB
- Replaces: 6 v2 packages (Mediator, Abstractions, DI, Validation.Fluent, Caching, Locking.Abstractions)
What It Is
IronAlpine.Mediator provides the application layer:
- Request/Response — decoupled command and query handlers
- Validation — FluentValidation integration + automatic behavior
- Caching — per-query TTL with automatic invalidation
- Behaviors — middleware pipeline (Slots 1-3 of 5)
Installation
dotnet add package IronAlpine.Mediator
Quick Setup
services.AddIronAlpineMediator(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(MyApplication).Assembly);
cfg.UseValidationBehavior(typeof(MyApplication).Assembly);
cfg.UseCachingBehavior(); // Optional
});
Define Requests & Handlers
Query (Read-Only)
// 1. Define request (immutable)
public class GetTimeOffByIdQuery : IRequest<TimeOffDetailsResponse>
{
public Guid TimeOffId { get; set; }
}
// 2. Define validator (FluentValidation)
public class GetTimeOffByIdQueryValidator : AbstractValidator<GetTimeOffByIdQuery>
{
public GetTimeOffByIdQueryValidator()
{
RuleFor(x => x.TimeOffId).NotEmpty();
}
}
// 3. Define handler
public class GetTimeOffByIdQueryHandler
: IRequestHandler<GetTimeOffByIdQuery, TimeOffDetailsResponse>
{
private readonly IRepository<TimeOff> _repository;
public async Task<TimeOffDetailsResponse> Handle(
GetTimeOffByIdQuery request,
CancellationToken cancellationToken)
{
var timeOff = await _repository.GetByIdAsync(request.TimeOffId, cancellationToken);
return new TimeOffDetailsResponse { ... };
}
}
// 4. Send request (in controller/service)
var response = await _mediator.Send(new GetTimeOffByIdQuery { TimeOffId = id });
Command (Mutation)
// 1. Define request
public class ApproveTimeOffCommand : IRequest<Unit>
{
public Guid TimeOffId { get; set; }
public string Comment { get; set; }
}
// 2. Define validator
public class ApproveTimeOffCommandValidator : AbstractValidator<ApproveTimeOffCommand>
{
public ApproveTimeOffCommandValidator()
{
RuleFor(x => x.TimeOffId).NotEmpty();
RuleFor(x => x.Comment).NotEmpty().MaximumLength(500);
}
}
// 3. Define handler
public class ApproveTimeOffCommandHandler
: IRequestHandler<ApproveTimeOffCommand, Unit>
{
private readonly IUnitOfWork _unitOfWork;
public async Task<Unit> Handle(ApproveTimeOffCommand request, CancellationToken ct)
{
var repo = _unitOfWork.Repository<TimeOff>();
var timeOff = await repo.GetByIdAsync(request.TimeOffId, ct);
timeOff.Approve(new UserId(Guid.NewGuid()), request.Comment);
repo.Update(timeOff);
await _unitOfWork.SaveChangesAsync(ct);
return Unit.Value;
}
}
// 4. Send command
await _mediator.Send(new ApproveTimeOffCommand { TimeOffId = id, Comment = "OK" });
Behavior Pipeline (Slots 1-3)
Mediator owns 3 of 5 behavior slots:
| Slot | Behavior | Purpose | Opt-In |
|---|---|---|---|
| 1 | LoggingBehavior | Logs request/response | Yes (Observability) |
| 2 | CachingBehavior | Caches query results | Yes |
| 3 | ValidationBehavior | Validates request | No (always on) |
Enable Caching
// appsettings.json
{
"IronAlpine": {
"Mediator": {
"Caching": {
"Enabled": true,
"DefaultTTLSeconds": 300 // 5 minutes
}
}
}
}
// Setup
services.AddIronAlpineMediator(cfg =>
{
cfg.UseCachingBehavior();
});
Enable Validation
// appsettings.json
{
"IronAlpine": {
"Mediator": {
"Validation": {
"Enabled": true
}
}
}
}
// Setup (required)
services.AddIronAlpineMediator(cfg =>
{
cfg.UseValidationBehavior(typeof(MyApplication).Assembly);
});
Configuration
{
"IronAlpine": {
"Mediator": {
"Validation": {
"Enabled": true,
"Assemblies": ["MyApp.Application"]
},
"Caching": {
"Enabled": true,
"DefaultTTLSeconds": 300
}
}
}
}
| Setting | Default | Purpose |
|---|---|---|
Validation.Enabled |
true | Enable FluentValidation behavior |
Caching.Enabled |
true | Enable query caching |
Caching.DefaultTTLSeconds |
300 | Cache TTL in seconds |
Custom Behaviors
Add your own behaviors to the pipeline:
// 1. Implement IPipelineBehavior<TRequest, TResponse>
public class MyCustomBehavior<TRequest, TResponse>
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
// Before handler
Console.WriteLine($"Handling {typeof(TRequest).Name}");
var response = await next();
// After handler
Console.WriteLine($"Handled {typeof(TRequest).Name}");
return response;
}
}
// 2. Register it
services.AddTransient(
typeof(IPipelineBehavior<,>),
typeof(MyCustomBehavior<,>));
Best Practices
✅ DO
// 1. Use single responsibility
public class GetTimeOffByIdQuery : IRequest<TimeOffDetailsResponse> { }
public class ApproveTimeOffCommand : IRequest<Unit> { }
// 2. Validate early
RuleFor(x => x.TimeOffId).NotEmpty();
// 3. Use interfaces
private readonly IRepository<TimeOff> _repository;
// 4. Handle cancellation
public async Task<TResponse> Handle(
TRequest request,
CancellationToken cancellationToken)
{
// Use cancellationToken in all async operations
return await _repository.GetByIdAsync(id, cancellationToken);
}
❌ DON'T
// 1. Bypass validation manually
if (request.TimeOffId == Guid.Empty) { ... } // Validator should do this
// 2. Catch validation exceptions
// Validation behavior handles them, return ProblemDetails automatically
// 3. Return Task instead of awaiting
return repository.GetByIdAsync(...); // Should be awaited
// 4. Ignore CancellationToken
public async Task<TResponse> Handle(TRequest request, CancellationToken ct)
{
return await _repository.GetByIdAsync(...); // Missing ct parameter
}
Integration with Other Packages
- IronAlpine.Kernel: Request types use domain types (TimeOffId, UserId, etc.)
- IronAlpine.Data: Handlers use IRepository<T>, IUnitOfWork for persistence
- IronAlpine.Observability: LoggingBehavior (Slot 1) added automatically
- IronAlpine.Web: Controllers send requests via mediator
Troubleshooting
Q: Validator not running?
A: Ensure UseValidationBehavior(assembly) called with correct assembly containing validators.
Q: Caching not working?
A: Set Mediator.Caching.Enabled: true and call UseCachingBehavior().
Q: Behavior order wrong?
A: Behaviors register in order. Check Program.cs Setup is: Mediator → Data → Observability.
Examples
See IRONALPINE_V3_DOCUMENTATION.md for detailed examples.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FluentValidation (>= 12.0.0)
- FluentValidation.DependencyInjectionExtensions (>= 12.0.0)
- IronAlpine.Kernel (>= 3.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.7)
-
net9.0
- FluentValidation (>= 12.0.0)
- FluentValidation.DependencyInjectionExtensions (>= 12.0.0)
- IronAlpine.Kernel (>= 3.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.7)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on IronAlpine.Mediator:
| Package | Downloads |
|---|---|
|
IronAlpine.Mediator.DependencyInjection
Dependency injection integration for IronAlpine mediator, including assembly scanning and open behavior registration. |
|
|
IronAlpine.Data
EFCore data stack for IronAlpine: repositories, interceptors (audit, soft-delete, versioning), mediator behaviors (AuditingBehavior, TransactionBehavior, UnitOfWork), domain event dispatching, and Redis cache. Unified entry point: AddIronAlpineData<TDbContext>. All implementations are internal. |
|
|
IronAlpine.EventBus
Kafka-backed event bus with outbox/inbox pattern, dead letter support, and replay functionality. Unified namespace: IronAlpine.EventBus. Kafka implementation is internal; only contracts and topology builder are public. SSL cert parameters fully configurable (SslCaLocation, SslCertLocation, SslKeyLocation, SslKeyPassword). |
|
|
IronAlpine.Observability
Logging (Serilog), OpenTelemetry tracing/metrics, and Resilience (Polly) for IronAlpine microservices. Provides UseLoggingBehavior() extension for the mediator pipeline. EventMetadataContext and correlation tracking included. All implementations internal. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Stable mediator release with request/response, notification publish strategies, streaming, and dependency injection integration.