Cayd.AspNetCore.Mediator 1.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Cayd.AspNetCore.Mediator --version 1.0.2
                    
NuGet\Install-Package Cayd.AspNetCore.Mediator -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cayd.AspNetCore.Mediator" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cayd.AspNetCore.Mediator" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Cayd.AspNetCore.Mediator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cayd.AspNetCore.Mediator --version 1.0.2
                    
#r "nuget: Cayd.AspNetCore.Mediator, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cayd.AspNetCore.Mediator@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cayd.AspNetCore.Mediator&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Cayd.AspNetCore.Mediator&version=1.0.2
                    
Install as a Cake Tool

About

This is a mediator library that handles request-handler-response flows for ASP.NET Core. It supports automatically matching requests with corresponding handlers as well as custom flows for all requets and/or specific ones.

How to Use

After installing the package, you can set up your own request-handler-response flow by using IAsyncRequest<TResponse> and IAsyncHandler<TRequest, TResponse>. Afterwards, you need to add the mediator to the dependency injection. So that, you can use the SendAsync method of the IMediator interface.

  • Creating Request-Handler-Response Flow:
using Cayd.AspNetCore.Mediator.Abstractions;

public class MyRequest : IAsyncRequest<MyResponse>
{
    // ... properties of the request
}

public class MyHandler : IAsyncHandler<MyRequest, MyResponse>
{
    // Example dependency injection
    private readonly ILogger<MyHandler> _logger;

    // You can inject dependencies if needed
    public MyHandler(ILogger<MyHandler> logger)
    {
        _logger = logger;  // example
    }

    public async Task<MyResponse> HandleAsync(MyRequest request, CancellationToken cancellationToken)
    {
        // ... handle the request and return the corresponding response
    }
}

public class MyResponse
{
    // ... properties of the response
}
  • Adding Mediator and Handlers:
/**
 * Minimal API - Program.cs
 */
using Cayd.AspNetCore.Mediator.DependencyInjection;

builder.Services.AddMediator(config =>
{
    // Add handlers from one assembly
    config.AddHandlersFromAssembly(Assembly.GetAssembly(typeof(MyClassInAssembly)!));

    // ... or from multiple assemblies
    config.AddHandlersFromAssemblies(Assembly.GetAssembly(typeof(MyClassInAssembly))!,
        Assembly.GetAssembly(typeof(MyClassInAnotherAssembly))!);
});


/**
 * .NET 5 - Startup.cs
 */
using Cayd.AspNetCore.Mediator.DependencyInjection;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMediator(config =>
        {
            // Add handlers from one assembly
            config.AddHandlersFromAssembly(Assembly.GetAssembly(typeof(MyClassInAssembly)!));

            // ... or from multiple assemblies
            config.AddHandlersFromAssemblies(Assembly.GetAssembly(typeof(MyClassInAssembly))!,
                Assembly.GetAssembly(typeof(MyClassInAnotherAssembly))!);
        });
    }
}
  • Sending Request:
using Cayd.AspNetCore.Mediator;

[ApiController]
public class MyController : ControllerBase
{
    private readonly IMediator _mediator;

    public MyController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpGet("example")]
    public async Task<IActionResult> Example()
    {
        var response = await _mediator.SendAsync(new MyRequest()
        {
            // ... properties of the request
        });

        // ... handle response
    }

    [HttpGet("example-with-cancellation")]
    public async Task<IActionResult> Example(CancellationToken cancellationToken)
    {
        var response = await _mediator.SendAsync(new MyRequest()
        {
            // ... properties of the request
        }, cancellationToken);

        // ... handle response
    }
}

Custom Flow

You can customize the default request-handler-response flow structure by adding your own custom flow elements for all requests and/or specific ones. To do that, you need to create a class implementing the IMediatorFlow<TRequest, TResponse> interface and add it via the dependency injection extension methods of the library.

  • Custom Flow Element For All Requets:

If you create a generic IMediatorFlow like below, this flow element is applied to all requests.

using Cayd.AspNetCore.Mediator.Abstractions;
using Cayd.AspNetCore.Mediator.Flows;

public class MyCustomMediatorFlow<TRequest, TResponse> : IMediatorFlow<TRequest, TResponse>
    where TRequest : IAsyncRequest<TResponse>
{
    // Example dependency injection
    private readonly ILogger<MyCustomMediatorFlow<TRequest, TResponse>> _logger;

    // You can inject dependencies if needed
    public MyCustomMediatorFlow(ILogger<MyCustomMediatorFlow<TRequest, TResponse>> logger)
    {
        _logger = logger;   // example
    }

    public async Task<TResponse> InvokeAsync(TRequest request, AsyncHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        // ... custom logic

        // Call the next one
        return await next();
    }
}
  • Custom Flow Element For Specific Request:

If you specify the request and response types while creating IMediatorFlow, the flow element is applied only to that specific request.

using Cayd.AspNetCore.Mediator.Flows;

public class MyCustomSpecificMediatorFlow : IMediatorFlow<MyRequest, MyResponse>
{
    // Example dependency injection
    private readonly ILogger<MyCustomSpecificMediatorFlow> _logger;

    // You can inject dependencies if needed
    public MyCustomMediatorFlow(ILogger<MyCustomSpecificMediatorFlow> logger)
    {
        _logger = logger;   // example
    }

    public async Task<MyResponse> InvokeAsync(MyRequest request, AsyncHandlerDelegate<MyResponse> next, CancellationToken cancellationToken)
    {
        // ... custom logic

        // Call the next one
        return await next();
    }
}
  • Adding Custom Flows:
services.AddMediator(config =>
{
    // ... add handlers

    config.AddTransientFlow(typeof(MyCustomMediatorFlow<,>));        // for all requests
    config.AddTransientFlow(typeof(MyCustomSpecificMediatorFlow));   // only for 'MyRequest'
});

NOTE: The order of added custom flow elements defines which one is invoked first.

Performance

  • The library has two different behaviors based on if any custom flow is added. If there is no custom flow, the request-handler-response flow skips looking for custom flows, which speeds up the process.
  • When a IAsyncRequest<TResponse> is sent, the library needs to generate a delegate to cache the related flow for the first time. This initial process adds a negligible overhead (less than 1ms according to the local tests) to the request, which also varies based on if there is any custom flow. Afterwards, when the same request is sent, the library uses the cached delegate to speed up the process.

Extras

For CQRS handlers utilizing the Cayd.AspNetCore.ExecResult and FluentValidation libraries, the validation flow can be set up as follows to use ExecBadRequest automatically when validations fail:

  • Validation Flow:
using Cayd.AspNetCore.ExecutionResult;
using Cayd.AspNetCore.ExecutionResult.ClientError;
using Cayd.AspNetCore.Mediator.Abstractions;
using Cayd.AspNetCore.Mediator.Flows;
using FluentValidation;

public class MediatorValidationFlow<TRequest, TResponse> : IMediatorFlow<TRequest, TResponse>
    where TRequest : IAsyncRequest<TResponse>
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public MediatorValidationFlow(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public async Task<TResponse> InvokeAsync(TRequest request, AsyncHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        foreach (var validator in _validators)
        {
            if (validator == null)
                continue;

            var validationResult = await validator.ValidateAsync(request, cancellationToken);
            if (validationResult.Errors.Count > 0)
            {
                var errorDetails = validationResult.Errors
                    .Select(e => new ExecErrorDetail(e.ErrorMessage, e.ErrorCode))
                    .ToList();

                return (dynamic)new ExecBadRequest(errorDetails);
            }
        }

        return await next();
    }
}
  • Example Validation in CQRS:
public class MyRequestValidation : AbstractValidator<MyRequest>
{
    public MyRequestValidation()
    {
        RuleFor(r => r.Property1)
            .NotEmpty()
                .WithMessage("Error message here")
                .WithErrorCode("Error message code here (can be used for translation keys for instance)");
    }
}
  • Adding The Validation Flow:
services.AddMediator(config =>
{
    // ...

    config.AddTransientFlow(typeof(MediatorValidationFlow<,>));
});
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net5.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 199 12/22/2025
1.0.2 218 8/13/2025
1.0.1 275 8/6/2025
1.0.0 268 8/6/2025

Update readme