Command Query Responsibility Segregation (CQRS) framework based on mediator pattern using Mongo DB as the data store handler
$ dotnet add package Arbiter.CommandQuery.MongoDBMediator pattern and Command Query Responsibility Segregation (CQRS) implementation in .NET
| Library | Package | Description |
|---|---|---|
| Arbiter.Mediation | Lightweight and extensible implementation of the Mediator pattern | |
| Arbiter.Mediation.OpenTelemetry | OpenTelemetry support for Arbiter.Mediation library | |
| Arbiter.CommandQuery | Base package for Commands, Queries and Behaviors | |
| Arbiter.CommandQuery.EntityFramework |
| Entity Framework Core handlers for the base Commands and Queries |
| Arbiter.CommandQuery.MongoDB | Mongo DB handlers for the base Commands and Queries |
| Arbiter.CommandQuery.Endpoints | Minimal API endpoints for base Commands and Queries |
| Arbiter.CommandQuery.Mvc | MVC Controllers for base Commands and Queries |
A lightweight and extensible implementation of the Mediator pattern for .NET applications, designed for clean, modular architectures like Vertical Slice Architecture and CQRS.
The Arbiter Mediation library is available on nuget.org via package name Arbiter.Mediation.
To install Arbiter Mediation, run the following command in the Package Manager Console
Install-Package Arbiter.MediationOR
dotnet add package Arbiter.MediationIRequest<TResponse> and IRequestHandler<TRequest, TResponse>INotification and INotificationHandler<TNotification>IPipelineBehavior<TRequest, TResponse>IServiceProviderArbiter.Mediation.OpenTelemetrypublic class Ping : IRequest<Pong>
{
public string? Message { get; set; }
}public class PingHandler : IRequestHandler<Ping, Pong>
{
public async ValueTask<Pong> Handle(
Ping request,
CancellationToken cancellationToken = default)
{
// Simulate some work
await Task.Delay(100, cancellationToken);
return new Pong { Message = $"{request.Message} Pong" };
}
}public class PingBehavior : IPipelineBehavior<Ping, Pong>
{
public async ValueTask<Pong> Handle(
Ping request,
RequestHandlerDelegate<Pong> next,
CancellationToken cancellationToken = default)
{
// Do something before the request is handled
var response = await next(cancellationToken);
// Do something after the request is handled
return response;
}
}// Register Mediator services
services.AddMediator();
// Register handlers
services.TryAddTransient<IRequestHandler<Ping, Pong>, PingHandler>();
// Optionally register pipeline behaviors, supports multiple behaviors
services.AddTransient<IPipelineBehavior<Ping, Pong>, PingBehavior>();public class PingController : ControllerBase
{
private readonly IMediator _mediator;
public PingController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
public async Task<IActionResult> Get(
string? message = null,
CancellationToken? cancellationToken = default)
{
var request = new Ping { Message = message };
var response = await _mediator.Send<Ping, Pong>(request, cancellationToken);
return Ok(response);
}
}OpenTelemetry support for Arbiter.Mediation library
Install-Package Arbiter.Mediation.OpenTelemetryOR
dotnet add package Arbiter.Mediation.OpenTelemetryRegister via dependency injection
services.AddMediatorDiagnostics();
services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddMediatorInstrumentation()
.AddConsoleExporter()
)
.WithMetrics(metrics => metrics
.AddMediatorInstrumentation()
.AddConsoleExporter()
);Command Query Responsibility Segregation (CQRS) framework based on mediator pattern
The Arbiter Command Query library is available on nuget.org via package name Arbiter.CommandQuery.
To install Arbiter Command Query, run the following command in the Package Manager Console
Install-Package Arbiter.CommandQueryOR
dotnet add package Arbiter.CommandQueryRegister Command Query services via dependency injection
services.AddCommandQuery();// sample user claims
var principal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "JohnDoe") }));
var query = new EntityIdentifierQuery<int, ProductReadModel>(principal, 123);
// Send the query to the mediator for execution
var result = await mediator.Send(query);var filter = new EntityFilter { Name = "Status", Operator = "eq", Value = "Active" };
var sort = new EntitySort { Name = "Name", Direction = "asc" };
var query = new EntitySelectQuery<ProductReadModel>(principal, filter, sort);
// Send the query to the mediator for execution
var result = await mediator.Send(query);var id = 123; // The ID of the entity to update
var updateModel = new ProductUpdateModel
{
Name = "Updated Product",
Description = "Updated description of the product",
Price = 29.99m
};
var command = new EntityUpdateCommand<int, ProductUpdateModel, ProductReadModel>(principal, id, updateModel);
// Send the command to the mediator for execution
var result = await mediator.Send(command);Entity Framework Core handlers for the base Commands and Queries
Install-Package Arbiter.CommandQuery.EntityFrameworkOR
dotnet add package Arbiter.CommandQuery.EntityFrameworkRegister via dependency injection
// Add Entity Framework Core services
services.AddDbContext<TrackerContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("TrackerConnection"))
);
// Register Command Query services
services.AddCommandQuery();
// Implement and register IMapper
services.AddSingleton<IMapper, MyMapper>();
// Implement and register IValidator
services.AddSingleton<IValidator, MyValidator>();
// Register Entity Framework Core handlers for each Entity
services.AddEntityQueries<TrackerContext, Product, int, ProductReadModel>();
services.AddEntityCommands<TrackerContext, Product, int, ProductReadModel, ProductCreateModel, ProductUpdateModel>();Mongo DB handlers for the base Commands and Queries
Install-Package Arbiter.CommandQuery.MongoDBOR
dotnet add package Arbiter.CommandQuery.MongoDBRegister via dependency injection
// Add MongoDB Repository services
services.AddMongoRepository("Tracker");
// Register Command Query services
services.AddCommandQuery();
// Implement and register IMapper
services.AddSingleton<IMapper, MyMapper>();
// Implement and register IValidator
services.AddSingleton<IValidator, MyValidator>();
// Register MongoDB handlers for each Entity
services.AddEntityQueries<IMongoEntityRepository<Product>, Product, string, ProductReadModel>();
services.AddEntityCommands<IMongoEntityRepository<Product>, Product, string, ProductReadModel, ProductCreateModel, ProductUpdateModel>();Minimal API endpoints for base Commands and Queries
Install-Package Arbiter.CommandQuery.EndpointsOR
dotnet add package Arbiter.CommandQuery.EndpointsRegister via dependency injection
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// add endpoints services
builder.Services.AddFeatureEndpoints();
var app = builder.Build();
// map endpoint routes
app.MapFeatureEndpoints();public class ProductEndpoint : EntityCommandEndpointBase<int, ProductReadModel, ProductReadModel, ProductCreateModel, ProductUpdateModel>
{
public ProductEndpoint(ILoggerFactory loggerFactory)
: base(loggerFactory, "Product")
{
}
}
// Register endpoint, must support duplicate (IEnumerable) IFeatureEndpoint registrations
builder.Services.AddTransient<IFeatureEndpoint, ProductEndpoint>();MVC Controllers for base Commands and Queries
Install-Package Arbiter.CommandQuery.MvcOR
dotnet add package Arbiter.CommandQuery.Mvc