Nast.SimpleMediator 1.0.2

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

SimpleMediator

A lightweight and efficient implementation of the Mediator pattern for .NET 8 applications. SimpleMediator provides a clean abstraction for handling commands, queries, and notifications while maintaining simplicity and performance.

Note: This library is designed as an educational implementation and is not intended as a commercial solution.

Features

  • Request/Response Pattern: Handle commands and queries with typed responses
  • Notifications: Event-driven architecture with one-to-many communication
  • Stream Requests: Support for asynchronous data streams using IAsyncEnumerable
  • Dependency Injection: Seamless integration with Microsoft.Extensions.DependencyInjection
  • Auto Registration: Automatic discovery and registration of handlers from assemblies
  • Custom Behaviors: Extensible pipeline for cross-cutting concerns
  • .NET 8 Native: Built specifically for .NET 8 with modern C# features

Installation

Add the package reference to your project:

dotnet add package Nast.SimpleMediator

Quick Start

Register SimpleMediator in your dependency injection container:

using Nast.SimpleMediator;

var builder = WebApplication.CreateBuilder(args);

// Basic registration - scans all loaded assemblies
builder.Services.AddMediator();

// Register specific assemblies
builder.Services.AddMediator(typeof(Program).Assembly);

// Advanced configuration
builder.Services.AddMediator(options =>
{
    options.RegisterServicesFromAssemblies(typeof(Program).Assembly);
    options.AddBehavior<ILoggingBehavior, LoggingBehavior>();
});

var app = builder.Build();

Usage

Requests and Responses

SimpleMediator supports both commands (requests without responses) and queries (requests with responses).

Define a Request
// Query with response
public record GetUserQuery(int UserId) : IRequest<User>;

// Command without response
public record CreateUserCommand(string Name, string Email) : IRequest;
Implement Request Handlers
public class GetUserHandler : IRequestHandler<GetUserQuery, User>
{
    private readonly IUserRepository _repository;

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

    public async Task<User> Handle(GetUserQuery request, CancellationToken cancellationToken)
    {
        return await _repository.GetByIdAsync(request.UserId);
    }
}

public class CreateUserHandler : IRequestHandler<CreateUserCommand>
{
    private readonly IUserRepository _repository;

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

    public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
    {
        var user = new User(request.Name, request.Email);
        await _repository.AddAsync(user);
    }
}
Use in Controllers
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IMediator _mediator;

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

    [HttpGet("{id}")]
    public async Task<User> GetUser(int id)
    {
        return await _mediator.Send(new GetUserQuery(id));
    }

    [HttpPost]
    public async Task CreateUser(CreateUserCommand command)
    {
        await _mediator.Send(command);
    }
}

Notifications

Notifications allow decoupled event-driven communication where multiple handlers can respond to a single event.

Define a Notification
public record UserCreatedNotification(int UserId, string Email) : INotification;
Implement Notification Handlers
public class EmailNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    private readonly IEmailService _emailService;

    public EmailNotificationHandler(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public async Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
    {
        await _emailService.SendWelcomeEmailAsync(notification.Email);
    }
}

public class LoggingNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    private readonly ILogger<LoggingNotificationHandler> _logger;

    public LoggingNotificationHandler(ILogger<LoggingNotificationHandler> logger)
    {
        _logger = logger;
    }

    public async Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
    {
        _logger.LogInformation("User {UserId} was created", notification.UserId);
    }
}
Publish Notifications
public class CreateUserHandler : IRequestHandler<CreateUserCommand>
{
    private readonly IUserRepository _repository;
    private readonly IMediator _mediator;

    public CreateUserHandler(IUserRepository repository, IMediator mediator)
    {
        _repository = repository;
        _mediator = mediator;
    }

    public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
    {
        var user = new User(request.Name, request.Email);
        await _repository.AddAsync(user);

        // Publish notification - all handlers will be executed
        await _mediator.Publish(new UserCreatedNotification(user.Id, user.Email));
    }
}

Stream Requests

Stream requests enable asynchronous data streaming using IAsyncEnumerable<T>.

Define a Stream Request
public record GetUsersStreamQuery(string Filter) : IStreamRequest<User>;
Implement Stream Handler
public class GetUsersStreamHandler : IStreamRequestHandler<GetUsersStreamQuery, User>
{
    private readonly IUserRepository _repository;

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

    public async IAsyncEnumerable<User> Handle(
        GetUsersStreamQuery request,
        [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        await foreach (var user in _repository.GetFilteredUsersAsync(request.Filter))
        {
            cancellationToken.ThrowIfCancellationRequested();
            yield return user;
        }
    }
}
Consume the Stream
[HttpGet("stream")]
public async IAsyncEnumerable<User> GetUsersStream(string filter)
{
    await foreach (var user in _mediator.CreateStream(new GetUsersStreamQuery(filter)))
    {
        yield return user;
    }
}

Extension Methods

SimpleMediator provides several convenience extension methods:

// Send multiple notifications
var notifications = new List<INotification>
{
    new UserCreatedNotification(1, "user1@example.com"),
    new UserCreatedNotification(2, "user2@example.com")
};

await _mediator.PublishAll(notifications);

// Use publisher directly
await _publisher.PublishAll(notifications);

Core Interfaces

Main Abstractions

  • IMediator: Primary interface combining ISender and IPublisher
  • ISender: Handles request/response operations and stream creation
  • IPublisher: Manages notification publishing

Request Abstractions

  • IRequest<TResponse>: Request expecting a typed response
  • IRequest: Request without response (command pattern)
  • IStreamRequest<TResponse>: Request for streaming data

Handler Abstractions

  • IRequestHandler<TRequest, TResponse>: Handles requests with responses
  • IRequestHandler<TRequest>: Handles requests without responses
  • INotificationHandler<TNotification>: Handles notifications
  • IStreamRequestHandler<TRequest, TResponse>: Handles stream requests

Custom Behaviors

You can extend SimpleMediator with custom behaviors for cross-cutting concerns:

public interface ILoggingBehavior
{
    Task ExecuteAsync(Func<Task> next);
}

public class LoggingBehavior : ILoggingBehavior
{
    private readonly ILogger<LoggingBehavior> _logger;

    public LoggingBehavior(ILogger<LoggingBehavior> logger)
    {
        _logger = logger;
    }

    public async Task ExecuteAsync(Func<Task> next)
    {
        _logger.LogInformation("Executing operation");
        await next();
        _logger.LogInformation("Operation completed");
    }
}

// Register behavior
builder.Services.AddMediator(options =>
{
    options.AddBehavior<ILoggingBehavior, LoggingBehavior>();
});

Requirements

  • .NET 8.0 or higher
  • Microsoft.Extensions.DependencyInjection.Abstractions 9.0.7

Architecture

SimpleMediator follows a clean architecture approach with clear separation of concerns:

  • Abstractions: Core interfaces defining contracts
  • Internal: Implementation details hidden from consumers
  • Extensions: Convenience methods for common operations
  • Registration: Dependency injection configuration

License

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

Product 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. 
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.2 214 7/9/2025
1.0.1 299 7/9/2025 1.0.1 is deprecated because it has critical bugs.
1.0.0 296 7/9/2025 1.0.0 is deprecated because it has critical bugs.