CleanBusMediator 1.0.5

There is a newer version of this package available.
See the version list below for details.
dotnet add package CleanBusMediator --version 1.0.5
                    
NuGet\Install-Package CleanBusMediator -Version 1.0.5
                    
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="CleanBusMediator" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CleanBusMediator" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="CleanBusMediator" />
                    
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 CleanBusMediator --version 1.0.5
                    
#r "nuget: CleanBusMediator, 1.0.5"
                    
#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 CleanBusMediator@1.0.5
                    
#: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=CleanBusMediator&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=CleanBusMediator&version=1.0.5
                    
Install as a Cake Tool

๐Ÿš CleanBusMediator

CleanBusMediator is a modern, modular, and extensible Command Bus / Mediator framework for .NET.
It promotes a clean separation of responsibilities through Commands, Events, Streaming, Middleware Pipelines, Exception Handling, and more โ€” all with full support for dependency injection and testability.

Think of it as your lightweight, powerful message dispatcher โ€” without the magic.


๐Ÿ“ฆ Installation

Coming soon to NuGet:

dotnet add package CleanBusMediator

๐Ÿ”ง Quick Setup

1. Register CleanBusMediator in your DI container

CleanBusMediator supports multiple registration styles:

builder.Services.CleanBusMediator(typeof(CreateUserHandler).Assembly);

This scans the specified assembly for:

  • Command handlers
  • Event handlers
  • Stream handlers
  • Middlewares
  • Exception handlers
  • Pre-/Post-processors

โžค Fluent configuration (advanced)
builder.Services.CleanBusMediator(config =>
{
    config.RegisterFromAssembly(typeof(CreateUserHandler).Assembly);

    // Optional: add your own middleware behaviors
    config.AddMiddleware(typeof(ResultValidationMiddleware<,>));
    config.AddMiddleware(typeof(MyCustomLoggingBehavior<,>));
});

โžค From Type (shorthand)
builder.Services.CleanBusMediator(typeof(CreateUserHandler));

โžค Fallback: auto-discover all assemblies (use with caution)
builder.Services.CleanBusMediator();

โš ๏ธ This will scan all loaded assemblies in AppDomain.CurrentDomain.
Use only in small apps, tests, or single-project setups.


โœ‰๏ธ Send Commands

Define a command

public class PingCommand : ICommand<string> { }

Handle the command

public class PingHandler : ICommandHandler<PingCommand, string>
{
    public Task<string> Handle(PingCommand command, CancellationToken cancellationToken)
        => Task.FromResult("Pong!");
}

Dispatch it

var result = await dispatcher.Send(new PingCommand());
// result: "Pong!"

๐Ÿ“ข Publish Events

Define an event

public class OrderPlaced : IEvent
{
    public Guid OrderId { get; set; }
}

Handle the event

public class SendConfirmationEmail : IEventHandler<OrderPlaced>
{
    public Task Handle(OrderPlaced notification, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Email sent for order {notification.OrderId}");
        return Task.CompletedTask;
    }
}

Publish it

await dispatcher.Publish(new OrderPlaced { OrderId = Guid.NewGuid() });

๐ŸŒ€ Streaming Commands

Define a stream command

public class StreamNumbers : IStreamCommand<int>
{
    public int Count { get; set; }
}

Handle it

public class StreamNumbersHandler : IStreamCommandHandler<StreamNumbers, int>
{
    public async IAsyncEnumerable<int> Handle(StreamNumbers command, CancellationToken cancellationToken)
    {
        for (int i = 0; i < command.Count; i++)
        {
            yield return i;
            await Task.Delay(100);
        }
    }
}

Consume the stream

await foreach (var number in dispatcher.Stream(new StreamNumbers { Count = 5 }))
{
    Console.WriteLine(number);
}

๐Ÿงฉ Middleware Support

Define a middleware

public class LoggingMiddleware<TCommand, TResult> : ICommandMiddleware<TCommand, TResult>
    where TCommand : ICommand<TResult>
{
    public async Task<TResult> Handle(TCommand command, CancellationToken cancellationToken, CommandHandlerDelegate<TResult> next)
    {
        Console.WriteLine($"[Start] {typeof(TCommand).Name}");
        var result = await next();
        Console.WriteLine($"[End] {typeof(TCommand).Name}");
        return result;
    }
}

Registered automatically if in the scanned assembly.


๐Ÿ›ก๏ธ Exception Handling

Define an exception handler

public class PingExceptionHandler : ICommandExceptionHandler<PingCommand, string>
{
    public Task<string> Handle(PingCommand command, Exception exception, CancellationToken cancellationToken)
    {
        return Task.FromResult("Recovered from error");
    }
}

๐Ÿงช Pre- and Post-Processors

Pre-processor

public class ValidatePing : ICommandPreProcessor<PingCommand>
{
    public Task Process(PingCommand command, CancellationToken cancellationToken)
    {
        Console.WriteLine("Pre-processing PingCommand");
        return Task.CompletedTask;
    }
}

Post-processor

public class LogPingResult : ICommandPostProcessor<PingCommand, string>
{
    public Task Process(PingCommand command, string result, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Post-processing result: {result}");
        return Task.CompletedTask;
    }
}

๐ŸŒ Event Middleware

public class EventLoggingMiddleware<TEvent> : IEventMiddleware<TEvent>
    where TEvent : IEvent
{
    public async Task Handle(TEvent @event, CancellationToken cancellationToken, EventHandlerDelegate next)
    {
        Console.WriteLine($"[Event Start] {@event.GetType().Name}");
        await next();
        Console.WriteLine($"[Event End] {@event.GetType().Name}");
    }
}

โšก Parallel Event Publishing

Optional: run event handlers in parallel

await dispatcher.PublishParallel(new OrderPlaced { OrderId = Guid.NewGuid() });

๐Ÿงช Testing Support

Fake Dispatcher

var dispatcher = new FakeDispatcher
{
    SendHandler = cmd => "FakeResult"
};

var result = await dispatcher.Send(new PingCommand());

Test Dispatcher (manual handler registration)

var testDispatcher = new TestDispatcher();
testDispatcher.RegisterHandler(new PingHandler());

var result = await testDispatcher.Send(new PingCommand());

๐Ÿ” Retry Policies

Custom retry logic per command:

public class SimpleRetryPolicyProvider : IRetryPolicyProvider
{
    public AsyncPolicy<TResult>? GetPolicy<TCommand, TResult>()
        where TCommand : ICommand<TResult>
    {
        return Policy<TResult>
            .Handle<Exception>()
            .WaitAndRetryAsync(3, retry => TimeSpan.FromMilliseconds(200));
    }
}

Used automatically via RetryMiddlewareFactory<,> if registered.


๐Ÿง  Scoped Pipeline Builder

Need different middlewares per request? Use ScopedCommandPipelineBuilder:

var scopedDispatcher = new Dispatcher(
    type => scopedProvider.GetRequiredService(type),
    new ScopedCommandPipelineBuilder(scopedProvider, defaultPipeline)
);

๐Ÿงฐ Built-in Middleware Available

  • โœ… LoggingMiddleware
  • โœ… ValidationMiddleware (via IValidator<>)
  • โœ… CachingMiddleware (for ICachableCommand)
  • โœ… RetryMiddleware (via IRetryPolicyProvider)

๐Ÿงพ License

Licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET 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 is compatible.  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 is compatible.  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.
  • net6.0

    • No dependencies.
  • net7.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.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.