Fluentish.Mediator.Generator 1.0.2

dotnet add package Fluentish.Mediator.Generator --version 1.0.2
                    
NuGet\Install-Package Fluentish.Mediator.Generator -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="Fluentish.Mediator.Generator" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fluentish.Mediator.Generator" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Fluentish.Mediator.Generator" />
                    
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 Fluentish.Mediator.Generator --version 1.0.2
                    
#r "nuget: Fluentish.Mediator.Generator, 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 Fluentish.Mediator.Generator@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=Fluentish.Mediator.Generator&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Fluentish.Mediator.Generator&version=1.0.2
                    
Install as a Cake Tool

Fluentish.Mediator

Fluentish.Mediator is a high-performance, source-generated mediator implementation for .NET.

Unlike traditional mediator libraries that rely on runtime reflection and service location pattern matching, Fluentish.Mediator moves the dispatch logic to compile-time. It generates strongly typed implementations of your module interfaces, providing immediate build-time feedback on missing handlers and ensuring zero-overhead dispatch at runtime.

Design Philosophy

This library prioritizes correctness, explicitness, and performance over "magic" or loose coupling via generic containers.

  1. Compile-Time Safety: Relationships between Requests, Handlers, and Modules are validated during the build. If a request does not have a registered handler, the project will not compile.
  2. Explicit Dependencies: Instead of injecting a generic IMediator that hides what a class actually does, you inject specific Modules (e.g., IUserModule). This makes architectural boundaries and dependencies explicit in your constructors.
  3. Zero Runtime Overhead: The library generates direct method calls to handlers. There is no MakeGenericType, Invoke, or dictionary lookups occurring during the "Send" phase.
  4. AOT Compatibility: Because it avoids runtime type scanning and reflection-based instantiation, it is naturally compatible with Native AOT.

Installation

Install the core library and the source generator via NuGet. You need both packages to enable the runtime types and the compile-time generation features.

Using the .NET CLI:

dotnet add package Fluentish.Mediator
dotnet add package Fluentish.Mediator.Generator

Or via PackageReference in your project file:

<ItemGroup>
  <PackageReference Include="Fluentish.Mediator" Version="1.0.0" />
  <PackageReference Include="Fluentish.Mediator.Generator" Version="1.0.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

Note: The Fluentish.Mediator.Generator is a development-only dependency that generates the C# code during compilation.

Architecture Overview

The library organizes logic into Modules. A Module is an interface definition that groups related capabilities. You define the interface, and the Source Generator implements the dispatch logic.

Core Concepts

  • Module: An interface inheriting IMediatorModule.
  • Request: A POCO implementing IRequest or IRequest<TResult>.
  • Handler: A class implementing IRequestHandler<TModule, TRequest, TResult>.
  • Registration: A partial method attribute [RegisterModule] that triggers DI generation.

Usage

1. Define a Module

Create an interface that represents a logical domain boundary. Inherit from IMediatorModule.

using Fluentish.Mediator;

namespace MyDomain.Features.Billing;

public interface IBillingModule : IMediatorModule
{
    // The source generator will populate this interface with
    // Execute() methods for every request bound to this module.
}

2. Define Requests and Handlers

Bind a handler to a specific module using the generic arguments in IRequestHandler.

public record GenerateInvoiceRequest(Guid OrderId) : IRequest<InvoiceDto>;

public class GenerateInvoiceHandler : IRequestHandler<IBillingModule, GenerateInvoiceRequest, InvoiceDto>
{
    public async Task<InvoiceDto> Handle(GenerateInvoiceRequest request)
    {
        // Business logic...
        return new InvoiceDto();
    }
}

3. Register Dependencies

Instead of manual services.AddTransient calls, use the [RegisterModule] attribute on a partial void method. The source generator produces the method body, registering the Module implementation and all associated handlers/middleware.

using Microsoft.Extensions.DependencyInjection;
using Fluentish.Mediator;
using MyDomain.Features.Billing;

public static partial class ServiceCollectionExtensions
{
    [RegisterModule(typeof(IBillingModule))]
    public static partial void AddBillingModule(IServiceCollection services);
}

4. Consumption

Inject the specific module interface into your consumers.

public class BillingController : ControllerBase
{
    private readonly IBillingModule _billing;

    public BillingController(IBillingModule billing)
    {
        _billing = billing;
    }

    [HttpPost("invoice")]
    public async Task<IActionResult> CreateInvoice(Guid orderId)
    {
        // The Execute method is strongly typed and auto-generated.
        // It resolves the correct handler from the DI container.
        var result = await _billing.Execute(new GenerateInvoiceRequest(orderId));
        return Ok(result);
    }
}

Middleware (Pipeline Behaviors)

Middleware allows you to intercept requests for logging, validation, or transaction management. Middleware is strictly typed and supports both global (per-module) and per-request scoping.

To implement middleware, implement IRequestMiddleware:

public class LoggingMiddleware<TRequest, TResult> : IRequestMiddleware<IBillingModule, TRequest, TResult>
    where TRequest : IRequest<TResult>
{
    private readonly ILogger<LoggingMiddleware<TRequest, TResult>> _logger;

    public LoggingMiddleware(ILogger<LoggingMiddleware<TRequest, TResult>> logger)
    {
        _logger = logger;
    }

    public async Task<TResult> Handle(TRequest request, RequestHandler<TRequest, TResult> next)
    {
        _logger.LogInformation("Processing {RequestType}", typeof(TRequest).Name);
        
        var result = await next(request);
        
        _logger.LogInformation("Completed {RequestType}", typeof(TRequest).Name);
        return result;
    }
}

The source generator automatically detects registered middleware in the container and chains them in the generated Execute implementation.

Module Composition

Modules can be composed to create aggregate boundaries using IComposedMediatorModule. This allows a parent module to expose the capabilities of child modules while maintaining a single injection point.

// Define sub-modules
public interface IInvoicingModule : IMediatorModule {}
public interface IPaymentModule : IMediatorModule {}

// Define a composite module
public interface IBillingSuperModule : 
    IMediatorModule,
    IComposedMediatorModule<IInvoicingModule>,
    IComposedMediatorModule<IPaymentModule>
{
}

The generator produces an implementation for IBillingSuperModule that routes requests to the appropriate underlying implementations of IInvoicingModule or IPaymentModule.

How it Works

  1. Parsing: The analyzer scans for interfaces inheriting IMediatorModule and classes implementing IRequestHandler.
  2. Mapping: It maps requests to handlers based on the generic arguments.
  3. Generation:
    • Interface Expansion: It generates a partial interface definition containing specific Execute(TRequest) overloads for every discovered handler.
    • Implementation: It generates a concrete class that implements the interface. This class accepts IServiceProvider to resolve handlers lazily.
    • DI Configuration: It generates the body of the partial method decorated with [RegisterModule], adding all necessary registrations to the IServiceCollection.

This architecture ensures that the "mediator" is not a dictionary of delegates at runtime, but a concrete, compiled class specifically built for your application's shape.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has 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
1.0.2 92 12/27/2025

Initial stable release.