EasyDispatch 1.0.7

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

EasyDispatch

A lightweight, simple Mediator library for .NET focused on ease-of-use and implementing the CQRS pattern.

NuGet Downloads License

Features

Simple API - Minimal boilerplate, intuitive API
CQRS Support - Clean separation of queries, commands, and notifications
Streaming Queries - Handle large datasets efficiently with IAsyncEnumerable
Pipeline Behaviors - Add cross-cutting concerns like logging and validation
Polymorphic Dispatch - Notifications handled by base class and interface handlers
Startup Validation - Catch missing handlers at application startup
OpenTelemetry Support - Built-in Activity tracing for observability

Installation

dotnet add package EasyDispatch

Quick Start

1. Register the Mediator

var builder = WebApplication.CreateBuilder(args);

// Register mediator and scan assembly for handlers
builder.Services.AddMediator(typeof(Program).Assembly);

var app = builder.Build();

2. Define a Query and Handler

// Query
public record GetUserQuery(int UserId) : IQuery<UserDto>;

// Handler
public class GetUserQueryHandler : IQueryHandler<GetUserQuery, UserDto>
{
    private readonly IUserRepository _repository;

    public GetUserQueryHandler(IUserRepository repository)
    {
        _repository = repository;
    }

    public async Task<UserDto> Handle(GetUserQuery query, CancellationToken cancellationToken)
    {
        var user = await _repository.GetByIdAsync(query.UserId, cancellationToken);
        return new UserDto(user.Id, user.Name, user.Email);
    }
}

3. Use the Mediator

public class UserController : ControllerBase
{
    private readonly IMediator _mediator;

    public UserController(IMediator mediator) => _mediator = mediator;

    [HttpGet("{id}")]
    public async Task<ActionResult<UserDto>> GetUser(int id)
    {
        var query = new GetUserQuery(id);
        var user = await _mediator.SendAsync(query);
        return Ok(user);
    }
}

Message Types

Queries - Read operations that return data

public record GetUserQuery(int UserId) : IQuery<UserDto>;

Commands - Write operations that modify state

public record CreateUserCommand(string Name, string Email) : ICommand<int>;
public record DeleteUserCommand(int UserId) : ICommand;

Notifications - Events with multiple handlers (pub/sub)

public record UserCreatedNotification(int UserId, string Name) : INotification;

Streaming Queries - Large datasets returned incrementally

public record GetOrdersStreamQuery(int PageSize) : IStreamQuery<OrderDto>;

Pipeline Behaviors

Add cross-cutting concerns like logging, validation, and caching:

builder.Services.AddMediator(typeof(Program).Assembly)
    .AddOpenBehavior(typeof(LoggingBehavior<,>))
    .AddOpenBehavior(typeof(ValidationBehavior<,>))
    .AddOpenBehavior(typeof(PerformanceBehavior<,>));

Configuration

builder.Services.AddMediator(options =>
{
    // Assemblies to scan
    options.Assemblies = new[] { typeof(Program).Assembly };
    
    // Handler lifetime (default: Scoped)
    options.HandlerLifetime = ServiceLifetime.Scoped;
    
    // Notification strategy (default: StopOnFirstException)
    options.NotificationPublishStrategy = NotificationPublishStrategy.ParallelWhenAll;
    
    // Startup validation (default: None)
    options.StartupValidation = StartupValidation.FailFast;
});

Documentation

Goto Wiki

Examples

Command with Response

public record CreateOrderCommand(
    int CustomerId,
    List<OrderItem> Items
) : ICommand<int>;

public class CreateOrderCommandHandler : ICommandHandler<CreateOrderCommand, int>
{
    public async Task<int> Handle(CreateOrderCommand command, CancellationToken ct)
    {
        var order = new Order { CustomerId = command.CustomerId, Items = command.Items };
        await _repository.AddAsync(order, ct);
        return order.Id;
    }
}

// Usage
var command = new CreateOrderCommand(customerId: 123, items);
int orderId = await mediator.SendAsync(command);

Notifications with Multiple Handlers

public record UserCreatedNotification(int UserId, string Email) : INotification;

// Handler 1: Send welcome email
public class SendWelcomeEmailHandler : INotificationHandler<UserCreatedNotification>
{
    public async Task Handle(UserCreatedNotification notification, CancellationToken ct)
    {
        await _emailService.SendWelcomeEmailAsync(notification.Email, ct);
    }
}

// Handler 2: Update analytics
public class UpdateAnalyticsHandler : INotificationHandler<UserCreatedNotification>
{
    public async Task Handle(UserCreatedNotification notification, CancellationToken ct)
    {
        await _analyticsService.TrackUserCreatedAsync(notification.UserId, ct);
    }
}

// Usage - both handlers execute
await mediator.PublishAsync(new UserCreatedNotification(userId, email));

Streaming Large Datasets

public record GetOrdersStreamQuery() : IStreamQuery<OrderDto>;

public class GetOrdersStreamQueryHandler : IStreamQueryHandler<GetOrdersStreamQuery, OrderDto>
{
    public async IAsyncEnumerable<OrderDto> Handle(
        GetOrdersStreamQuery query,
        [EnumeratorCancellation] CancellationToken ct)
    {
        await foreach (var order in _repository.StreamAllOrdersAsync(ct))
        {
            yield return new OrderDto(order.Id, order.Total);
        }
    }
}

// Usage - process items as they arrive
await foreach (var order in mediator.StreamAsync(new GetOrdersStreamQuery()))
{
    Console.WriteLine($"Order {order.Id}: ${order.Total}");
}

Requirements

  • .NET 9.0 or later
  • Microsoft.Extensions.DependencyInjection 9.0+

License

This project is licensed under the MIT License - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET 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.

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.7 262 10/9/2025
1.0.6 233 10/8/2025
1.0.5 165 10/7/2025
1.0.2 164 10/7/2025
1.0.1 163 10/7/2025
1.0.0 240 10/7/2025 1.0.0 is deprecated because it has critical bugs.