Flowsy.Mediation
13.0.1
dotnet add package Flowsy.Mediation --version 13.0.1
NuGet\Install-Package Flowsy.Mediation -Version 13.0.1
<PackageReference Include="Flowsy.Mediation" Version="13.0.1" />
<PackageVersion Include="Flowsy.Mediation" Version="13.0.1" />
<PackageReference Include="Flowsy.Mediation" />
paket add Flowsy.Mediation --version 13.0.1
#r "nuget: Flowsy.Mediation, 13.0.1"
#:package Flowsy.Mediation@13.0.1
#addin nuget:?package=Flowsy.Mediation&version=13.0.1
#tool nuget:?package=Flowsy.Mediation&version=13.0.1
Flowsy Mediation
This package provides a simple but useful implementation of the mediator pattern for .NET applications. As of version 13, this packagke no longer depends on MediatR and provides its own implementation of the mediator pattern, which is designed to be lightweight and easy to use. For request validation, it still can use FluentValidation if you configure it to do so.
Concepts
The mediator pattern allows us to centralize communication between different parts of an application through a single mediator object in charge of dispatching requests and notifications to the appropriate components containing the logic to handle them.
A common application flow would be:
- User requests some action to be executed.
- The application validates the request and returns some error information to the user in case of invalid input.
- The application executes the requested operation.
- The application returns to the user the result of the operation or some error information if something went wrong during the process.
- After the request has been fulfilled, the application may notify other parts of the system to trigger another related operation.
In fact, the mediator pattern is a powerful way to implement the CQRS (Command Query Responsibility Segregation) pattern, which separates the read and write operations of an application.
- Query: A request for reading data with no alteration of the application's current state.
- Command: A request for creating, updating or removing data, thus altering the application's current state.
Requests
In the context of the mediation pattern, a request is an object that represents an operation to be performed and it contains all the necessary information to execute that operation. Some requests can execute wihout returning any result, while others can return a response.
IRequest
: Represents a request without a response.IRequest<TResponse>
: Represents a request that returns a response of typeTResponse
.
Request Handlers
A request handler is a component containing the logic to execute a request. It is responsible for processing the request and returning a response if applicable.
IRequestHandler<TRequest>
: Represents a handler for a request of typeTRequest
without a response.IRequestHandler<TRequest, TResponse>
: Represents a handler for a request of typeTRequest
that returns a response of typeTResponse
.
Notifications
Notifications contain information about relevant events that have occurred in the application and are published by the mediation system wihtout expecting a response.
INotification
: Represents a notification that can be published to subscribers.
Notifications Handlers
A notification handler is a component that processes notifications published by the mediation system. This concept is a powerful way to trigger side effects or notify other parts of the system about changes without requiring a response.
INotificationHandler<TNotification>
: Represents a handler for a notification of typeTNotification
.
Middleware
Middleware components can be used to intercept and process requests and notifications before they reach the associated handler. For instance, you can use a middleware to count the number of attempts to execute a given request, or to record audit trails for the request execution.
IRequestMiddleware<TRequest>
: Represents a middleware that can intercept and process requests of typeTRequest
before they reach the handler.IRequestMiddleware<TRequest, TResponse>
: Represents a middleware that can intercept and process requests of typeTRequest
with a response of typeTResponse
before they reach the handler.INotificationMiddleware<TNotification>
: Represents a middleware that can intercept and process notifications of typeTNotification
before they reach the handler.
Built-in Middleware
This package provides some built-in middleware components to facilitate common tasks:
Logging
RequestLoggingMiddleware<TRequest>
: Logs information about a request of typeTRequest
.RequestLoggingMiddleware<TRequest, TResponse>
: Logs information about a request of typeTRequest
and its response of typeTResponse
.NotificationLoggingMiddleware<TNotification>
: Logs information about a notification of typeTNotification
.
Validation
RequestValidationMiddleware<TRequest>
: Validates requests of typeTRequest
.RequestValidationMiddleware<TRequest, TResponse>
: Validates requests of typeTRequest
with a response of typeTResponse
.
Usage
1. Define Some Queries
// Queries/CustomersByRegion/CustomersByRegionQuery.cs
// using ...
using Flowsy.Mediation;
// using ...
// You can use classes or records to define your queries.
public record CustomersByRegionQuery(string CountryId, string? StateId) : IRequest<IEnumerable<CustomerDto>>;
2. Define Some Query Validators
// Queries/CustomersByRegion/CustomersByRegionQueryValidator.cs
// using ...
using Flowsy.Mediation;
using FluentValidation;
// using ...
public class CustomersByRegionQueryValidator : AbstractValidator<CustomersByRegionQuery>
{
public CustomersByRegionQueryValidator()
{
RuleFor(query => query.CountryId)
.NotEmpty()
.WithMessage("Country identifier is required.");
}
}
3. Define Some Query Handlers
// Queries/CustomersByRegion/CustomersByRegionQueryHandler.cs
// using ...
using Flowsy.Mediation;
// using ...
public class CustomersByRegionQueryHandler : IRequestHandler<CustomerByIdQuery, IEnumerable<CustomerDto>>
{
private readonly ICustomerRepository _customerRepository;
public CustomersByRegionQueryHandler(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
protected override async Task<IEnumerable<CustomerDto>> HandleAsync(CustomersByRegionQuery request, CancellationToken cancellationToken)
{
var customers = await _customerRepository.GetCusomtersByRegionAsync(request.CountryId, request.StateId, cancellationToken);
return customers;
}
}
4. Define Some Commands
// Commands/CreateCustomer/CreateCustomerCommand.cs
// using ...
using Flowsy.Mediation;
// using ...
// You can use classes or records to define your commands.
public record CreateCustomerCommand(string FirstName, string LastName, string Email) : IRequest<CreateCustomerCommandResult>;
5. Define Some Command Validators
// Commands/CreateCustomer/CreateCustomerCommandValidator.cs
// using ...
using Flowsy.Mediation;
using FluentValidation;
// using ...
public class CreateCustomerCommandValidator : AbstractValidator<CreateCustomerCommand>
{
public CreateCustomerCommandValidator()
{
RuleFor(command => command.FirstName)
.NotEmpty()
.WithMessage("First name is required.");
RuleFor(command => command.Email)
.EmailAddress()
.WithMessage("Invalid email address")
.DependentRules(() =>
{
RuleFor(command => command.Email)
.NotEmpty()
.WithMessage("Email is required.")
.MaximumLength(320)
.WithMessage("Up to 320 characters.");
});
}
}
6. Define Some Command Results
// Commands/CreateCustomer/CreateCustomerCommandResult.cs
// You can use classes or records to define your command results.
public record CreateCustomerCommandResult(Guid CustomerId);
7. Define Some Command Handlers
// Commands/CreateCustomer/CreateCustomerCommandHandler.cs
// using ...
using Flowsy.Mediation;
// using ...
public class CreateCustomerCommandHandler : IRequestHandler<CreateCustomerCommand, CreateCustomerCommandResult>
{
private readonly ICustomerRepository _customerRepository;
public CreateCustomerCommandHandler(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
protected override async Task<CreateCustomerCommandResult> HandleAsync(CreateCustomerCommand request, CancellationToken cancellationToken)
{
var customer = new Customer(Guid.NewGuid(), request.FirstName, request.LastName, request.Email);
await _customerRepository.CreateCustomerAsync(customer, cancellationToken);
return new CreateCustomerCommandResult(customer.CustomerId);
}
}
8. Register and Configure Services
// Program.cs
// using ...
using Flowsy.Mediation;
using FluentValidation;
// using ...
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddMediation()
.FromAssemblies(Assembly.GetExecutingAssembly()) // Add one or more assemblies containing your requests, notifications, validators and handlers
// .FromAssemblies([Assembly.GetExecutingAssembly()], false) // Use this version to prevent automatic registration of FluentValidation validators
.WithMiddleware() // Allow middleware registration
.ForLogging(LogLevel.Debug, true, true, true) // Built-in logging middleware for requests and notifications
.ForRequest(typeof(AuditMiddleware<>)) // Fictitious middleware for auditing requests without a response
.ForRequest(typeof(AuditMiddleware<,>)) // Fictitious middleware for auditing requests with a response
.ForRequest<CustomerCreationAttemptMiddleware>() // Fictitious middleware for counting attempts to create a customer
.ForValidation() // Built-in validation middleware for requests
.ForNotification<CustomerCreationCompletedMiddleware>(); // Fictitious middleware for handling customer creation completion notifications
//!!!!!!!!!!!
// IMPORTANT: The order of middleware registration matters, as they will be executed in the order they are registered.
//!!!!!!!!!!!
// Add other services
var app = builder.Build();
// Use services
app.Run();
9. Using the Mediator
// SomeController.cs
// using ...
using Flowsy.Mediation;
// using ...
[Route("api/[controller]")]
public class CustomersController : ControllerBase
{
private readonly IMediator _mediator;
public SomeController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
public async Task<IActionResult> GetCustomersByRegion([FromQuery] string countryId, [FromQuery] string? stateId)
{
var query = new CustomersByRegionQuery(countryId, stateId);
var customers = await _mediator.Send(query);
return Ok(customers);
}
[HttpPost]
public async Task<IActionResult> CreateCustomer(CreateCustomerCommand command)
{
var result = await _mediator.Send(command);
return CreatedAtAction(nameof(GetCustomerById), new { id = result.CustomerId }, result);
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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 was computed. 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. |
-
net8.0
- FluentValidation (>= 12.0.0)
- FluentValidation.DependencyInjectionExtensions (>= 12.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Flowsy.Mediation:
Package | Downloads |
---|---|
Flowsy.Web.Api
Foundation components for Web APIs. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
13.0.1 | 139 | 6/4/2025 |
13.0.0 | 146 | 6/4/2025 |
12.0.0 | 147 | 12/4/2024 |
11.0.4 | 213 | 1/17/2024 |
11.0.3 | 135 | 1/17/2024 |
11.0.2 | 135 | 1/17/2024 |
11.0.1 | 142 | 1/16/2024 |
11.0.0 | 147 | 1/16/2024 |
10.0.0 | 150 | 1/16/2024 |
9.0.2 | 187 | 12/14/2023 |
9.0.1 | 132 | 12/14/2023 |
9.0.0 | 131 | 12/14/2023 |
8.0.1 | 140 | 12/6/2023 |
8.0.0 | 154 | 12/5/2023 |
7.3.2 | 258 | 10/5/2023 |
7.3.1 | 172 | 10/5/2023 |
7.3.0 | 162 | 10/5/2023 |
7.2.1 | 190 | 10/4/2023 |
7.2.0 | 165 | 10/4/2023 |
7.1.0 | 164 | 10/4/2023 |
7.0.0 | 291 | 8/29/2023 |
6.1.7 | 414 | 6/2/2023 |
6.1.6 | 222 | 5/24/2023 |
6.1.5 | 171 | 5/24/2023 |
6.1.4 | 374 | 3/25/2023 |
6.1.3 | 425 | 3/10/2023 |
6.1.2 | 324 | 3/10/2023 |
6.1.1 | 343 | 3/10/2023 |
6.1.0 | 269 | 3/10/2023 |
6.0.3 | 317 | 3/9/2023 |
6.0.2 | 338 | 3/9/2023 |
6.0.1 | 393 | 3/9/2023 |
6.0.0 | 336 | 3/9/2023 |
5.1.1 | 378 | 2/27/2023 |
5.1.0 | 359 | 2/24/2023 |
5.0.0 | 355 | 2/23/2023 |
4.1.0 | 347 | 2/22/2023 |
4.0.0 | 418 | 2/21/2023 |
3.4.0 | 343 | 2/21/2023 |
3.3.0 | 261 | 2/21/2023 |
3.2.0 | 470 | 2/21/2023 |
3.1.0 | 285 | 2/21/2023 |
3.0.1 | 1,783 | 11/6/2022 |
3.0.0 | 686 | 11/5/2022 |
2.0.0 | 789 | 11/3/2022 |
1.1.2 | 383 | 11/2/2022 |
1.1.1 | 581 | 11/2/2022 |
1.1.0 | 389 | 11/2/2022 |
1.0.0 | 395 | 11/2/2022 |