![]() |
VOOZH | about |
dotnet add package Indiko.Blocks.Mediation.Abstractions --version 2.8.0
NuGet\Install-Package Indiko.Blocks.Mediation.Abstractions -Version 2.8.0
<PackageReference Include="Indiko.Blocks.Mediation.Abstractions" Version="2.8.0" />
<PackageVersion Include="Indiko.Blocks.Mediation.Abstractions" Version="2.8.0" />Directory.Packages.props
<PackageReference Include="Indiko.Blocks.Mediation.Abstractions" />Project file
paket add Indiko.Blocks.Mediation.Abstractions --version 2.8.0
#r "nuget: Indiko.Blocks.Mediation.Abstractions, 2.8.0"
#:package Indiko.Blocks.Mediation.Abstractions@2.8.0
#addin nuget:?package=Indiko.Blocks.Mediation.Abstractions&version=2.8.0Install as a Cake Addin
#tool nuget:?package=Indiko.Blocks.Mediation.Abstractions&version=2.8.0Install as a Cake Tool
Core abstractions for implementing CQRS (Command Query Responsibility Segregation) and Mediator patterns in the Indiko framework.
This package provides the fundamental contracts for building applications using the Mediator pattern and CQRS architecture, enabling clean separation between queries and commands with support for pipeline behaviors and notifications.
dotnet add package Indiko.Blocks.Mediation.Abstractions
Central interface for sending requests and publishing notifications.
public interface IMediator
{
// Send a request and get a response
Task<TResponse> Send<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest<TResponse>;
// Send a command (returns bool)
Task Send<TRequest>(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest;
// Publish a notification to multiple handlers
Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification;
}
Marker interface for commands (write operations).
// Command that returns a specific result
public interface ICommand<out TResult> : IRequest<TResult>
{
}
// Command that returns bool (success/failure)
public interface ICommand : ICommand<bool>
{
}
Marker interface for queries (read operations).
// Query that returns a specific result
public interface IQuery<out TResult> : IRequest<TResult>
{
}
// Query that returns a collection
public interface IQuery : IQuery<IEnumerable<IResult>>
{
}
Handler interface for processing requests.
public interface IRequestHandler<in TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
}
Pub/sub notification pattern.
public interface INotification
{
// Marker interface
}
public interface INotificationHandler<in TNotification>
where TNotification : INotification
{
Task Handle(TNotification notification, CancellationToken cancellationToken);
}
Cross-cutting concern pipeline.
public interface IPipelineBehavior<in TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken);
}
// Define a command
public class CreateUserCommand : ICommand<Guid>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
// Implement command handler
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
{
private readonly IUserRepository _userRepository;
private readonly IUnitOfWork _unitOfWork;
public CreateUserCommandHandler(IUserRepository userRepository, IUnitOfWork unitOfWork)
{
_userRepository = userRepository;
_unitOfWork = unitOfWork;
}
public async Task<Guid> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
var user = new User
{
Id = Guid.NewGuid(),
FirstName = request.FirstName,
LastName = request.LastName,
Email = request.Email
};
await _userRepository.AddAsync(user, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);
return user.Id;
}
}
// Use in controller
[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] CreateUserCommand command)
{
var userId = await _mediator.Send<CreateUserCommand, Guid>(command);
return CreatedAtAction(nameof(GetUser), new { id = userId }, userId);
}
// Define a query
public class GetUserByIdQuery : IQuery<UserDto>
{
public Guid UserId { get; set; }
}
// Implement query handler
public class GetUserByIdQueryHandler : IRequestHandler<GetUserByIdQuery, UserDto>
{
private readonly IUserRepository _userRepository;
public GetUserByIdQueryHandler(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task<UserDto> Handle(GetUserByIdQuery request, CancellationToken cancellationToken)
{
var user = await _userRepository.ReadByIdAsync(request.UserId, cancellationToken);
if (user == null)
return null;
return new UserDto
{
Id = user.Id,
FullName = $"{user.FirstName} {user.LastName}",
Email = user.Email
};
}
}
// Use in controller
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(Guid id)
{
var query = new GetUserByIdQuery { UserId = id };
var user = await _mediator.Send<GetUserByIdQuery, UserDto>(query);
return user != null ? Ok(user) : NotFound();
}
public class GetUsersPagedQuery : IQuery<PagedList<UserDto>>
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 20;
public string SearchTerm { get; set; }
}
public class GetUsersPagedQueryHandler : IRequestHandler<GetUsersPagedQuery, PagedList<UserDto>>
{
private readonly IUserRepository _userRepository;
public async Task<PagedList<UserDto>> Handle(GetUsersPagedQuery request, CancellationToken cancellationToken)
{
var users = await _userRepository.ReadManyByQueryPagedAsync(
where: u => string.IsNullOrEmpty(request.SearchTerm) ||
u.FirstName.Contains(request.SearchTerm) ||
u.LastName.Contains(request.SearchTerm),
page: request.PageNumber,
pageSize: request.PageSize,
cancellationToken: cancellationToken
);
return new PagedList<UserDto>(
users.Select(u => new UserDto { /* map properties */ }),
users.TotalCount,
users.CurrentPage,
users.PageSize
);
}
}
// Define notification
public class UserCreatedNotification : INotification
{
public Guid UserId { get; set; }
public string Email { get; set; }
}
// Multiple handlers can handle the same notification
public class SendWelcomeEmailHandler : INotificationHandler<UserCreatedNotification>
{
private readonly IEmailService _emailService;
public async Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
{
await _emailService.SendWelcomeEmailAsync(notification.Email);
}
}
public class CreateUserProfileHandler : INotificationHandler<UserCreatedNotification>
{
private readonly IProfileService _profileService;
public async Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
{
await _profileService.CreateDefaultProfileAsync(notification.UserId);
}
}
// Publish notification
await _mediator.Publish(new UserCreatedNotification
{
UserId = user.Id,
Email = user.Email
});
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0)
{
throw new ValidationException(failures);
}
}
return await next();
}
}
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
var requestName = typeof(TRequest).Name;
_logger.LogInformation($"Handling {requestName}");
var stopwatch = Stopwatch.StartNew();
try
{
var response = await next();
stopwatch.Stop();
_logger.LogInformation(
$"Handled {requestName} in {stopwatch.ElapsedMilliseconds}ms");
return response;
}
catch (Exception ex)
{
stopwatch.Stop();
_logger.LogError(ex,
$"Error handling {requestName} after {stopwatch.ElapsedMilliseconds}ms");
throw;
}
}
}
public class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>, ICacheableQuery
{
private readonly IDistributedCache _cache;
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
var cacheKey = request.GetCacheKey();
var cachedResponse = await _cache.GetStringAsync(cacheKey, cancellationToken);
if (cachedResponse != null)
{
return JsonSerializer.Deserialize<TResponse>(cachedResponse);
}
var response = await next();
await _cache.SetStringAsync(
cacheKey,
JsonSerializer.Serialize(response),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
},
cancellationToken);
return response;
}
}
public interface ISaga
{
Task ExecuteAsync(CancellationToken cancellationToken = default);
Task CompensateAsync(CancellationToken cancellationToken = default);
}
// Example: Order Processing Saga
public class OrderProcessingSaga : ISaga
{
private readonly IMediator _mediator;
public OrderProcessingSaga(IMediator mediator)
{
_mediator = mediator;
}
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{
// Step 1: Reserve inventory
await _mediator.Send(new ReserveInventoryCommand { ... }, cancellationToken);
// Step 2: Process payment
await _mediator.Send(new ProcessPaymentCommand { ... }, cancellationToken);
// Step 3: Create shipment
await _mediator.Send(new CreateShipmentCommand { ... }, cancellationToken);
}
public async Task CompensateAsync(CancellationToken cancellationToken = default)
{
// Rollback in reverse order
await _mediator.Send(new CancelShipmentCommand { ... }, cancellationToken);
await _mediator.Send(new RefundPaymentCommand { ... }, cancellationToken);
await _mediator.Send(new ReleaseInventoryCommand { ... }, cancellationToken);
}
}
public class Startup : WebStartup
{
public override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);
// Register mediator implementation
services.AddMediator(options =>
{
// Scan assemblies for handlers
options.RegisterServicesFromAssembly(typeof(Startup).Assembly);
// Register pipeline behaviors
options.AddBehavior<ValidationBehavior<,>>();
options.AddBehavior<LoggingBehavior<,>>();
options.AddBehavior<CachingBehavior<,>>();
});
}
}
CreateUserCommand, UpdateOrderCommandGetUserByIdQuery, GetOrdersPagedQueryCreateUserCommandHandler, GetUserByIdQueryHandlerIndiko.Blocks.Common.AbstractionsSee LICENSE file in the repository root.
Indiko.Blocks.Mediation.Mediator - MediatR-based implementationIndiko.Blocks.Mediation.SimpleMediator - Lightweight implementationIndiko.Blocks.EventBus.Abstractions - Event-driven architectureIndiko.Common.Abstractions - Common models and interfaces| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 3 NuGet packages that depend on Indiko.Blocks.Mediation.Abstractions:
| Package | Downloads |
|---|---|
|
Indiko.Blocks.Mediation.Mediator
Building Blocks Mediation Mediator |
|
|
Indiko.Blocks.Widget.Common.Abstractions
Building Blocks Widget Common Abstractions |
|
|
Indiko.Blocks.Mediation.SimpleMediator
Building Blocks Mediation Custom Mediator implemtation called SimpleMediator. Supports Request Handling, Notification and Pipeline Behaviors. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.8.0 | 197 | 5/22/2026 |
| 2.7.8 | 156 | 5/7/2026 |
| 2.7.7 | 114 | 5/7/2026 |
| 2.7.6 | 174 | 4/23/2026 |
| 2.7.5 | 174 | 4/23/2026 |
| 2.7.4 | 120 | 4/23/2026 |
| 2.7.3 | 118 | 4/23/2026 |
| 2.7.2 | 121 | 4/23/2026 |
| 2.7.1 | 116 | 4/23/2026 |
| 2.7.0 | 136 | 4/23/2026 |
| 2.6.4 | 166 | 4/21/2026 |
| 2.6.3 | 121 | 4/21/2026 |
| 2.6.2 | 144 | 4/21/2026 |
| 2.6.1 | 116 | 4/18/2026 |
| 2.6.0 | 121 | 4/17/2026 |
| 2.5.1 | 144 | 4/14/2026 |
| 2.5.0 | 190 | 3/30/2026 |
| 2.2.18 | 152 | 3/8/2026 |
| 2.2.17 | 131 | 3/8/2026 |
| 2.2.16 | 135 | 3/8/2026 |