SkillAgentSearch skills...

Mediator.Net

A simple mediator for .Net for sending command, publishing event and request response with pipelines supported

Install / Use

/learn @mayuanyang/Mediator.Net
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Mediator.Net

Stack Overflow Build Status CI Release codecov NuGet

A powerful and flexible mediator implementation for .NET that enables clean architecture by decoupling request/response handling through the mediator pattern.

<p align="center"> <img src="https://cloud.githubusercontent.com/assets/3387099/24353370/97f573f0-1330-11e7-890c-85855628a575.png" alt="Mediator.Net Logo" width="200"/> </p>

🌐 Languages

📋 Table of Contents

🚀 Features

  • Command/Query Separation: Clear separation between commands, queries, and events
  • Pipeline Support: Extensible middleware pipeline for cross-cutting concerns
  • Streaming Support: Handle multiple responses with IAsyncEnumerable
  • Dependency Injection: Built-in support for popular IoC containers
  • Event Publishing: Publish events from within handlers
  • Flexible Registration: Both explicit and assembly scanning registration
  • Middleware Ecosystem: Rich collection of pre-built middlewares

📦 Installation

Install the main package via NuGet:

Install-Package Mediator.Net

Or via .NET CLI:

dotnet add package Mediator.Net

🏁 Quick Start

Basic Setup

// Create and configure mediator
var mediaBuilder = new MediatorBuilder();
var mediator = mediaBuilder.RegisterHandlers(typeof(Program).Assembly).Build();

Define Messages and Handlers

// Command (no response)
public class CreateUserCommand : ICommand
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand>
{
    public async Task Handle(IReceiveContext<CreateUserCommand> context, CancellationToken cancellationToken)
    {
        // Handle the command
        var user = new User(context.Message.Name, context.Message.Email);
        // Save user...
        
        // Publish an event
        await context.Publish(new UserCreatedEvent { UserId = user.Id });
    }
}

// Request/Response
public class GetUserQuery : IRequest<UserDto>
{
    public int UserId { get; set; }
}

public class GetUserQueryHandler : IRequestHandler<GetUserQuery, UserDto>
{
    public async Task<UserDto> Handle(IReceiveContext<GetUserQuery> context, CancellationToken cancellationToken)
    {
        // Handle the query and return response
        return new UserDto { Id = context.Message.UserId, Name = "John Doe" };
    }
}

// Event
public class UserCreatedEvent : IEvent
{
    public int UserId { get; set; }
}

public class UserCreatedEventHandler : IEventHandler<UserCreatedEvent>
{
    public async Task Handle(IReceiveContext<UserCreatedEvent> context, CancellationToken cancellationToken)
    {
        // Handle the event
        Console.WriteLine($"User {context.Message.UserId} was created!");
    }
}

📋 Usage Examples

Sending Commands

// Command with no response
await mediator.SendAsync(new CreateUserCommand 
{ 
    Name = "John Doe", 
    Email = "john@example.com" 
});

// Command with response
var result = await mediator.SendAsync<CreateUserCommand, CreateUserResponse>(
    new CreateUserCommand { Name = "Jane Doe", Email = "jane@example.com" });

Handling Requests

// Request with response
var user = await mediator.RequestAsync<GetUserQuery, UserDto>(
    new GetUserQuery { UserId = 123 });

Publishing Events

// Publish event to all handlers
await mediator.Publish(new UserCreatedEvent { UserId = 123 });

Streaming Responses

Create handlers that return multiple responses:

public class GetMultipleUsersStreamHandler : IStreamRequestHandler<GetUsersQuery, UserDto>
{
    public async IAsyncEnumerable<UserDto> Handle(
        IReceiveContext<GetUsersQuery> context, 
        [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        for (var i = 0; i < 10; i++)
        {
            await Task.Delay(100, cancellationToken);
            yield return new UserDto { Id = i, Name = $"User {i}" };
        }
    }
}

// Consume the stream
await foreach (var user in mediator.CreateStream<GetUsersQuery, UserDto>(new GetUsersQuery()))
{
    Console.WriteLine($"Received: {user.Name}");
}

🔧 Handler Registration

Assembly Scanning (Recommended)

var mediator = new MediatorBuilder()
    .RegisterHandlers(typeof(Program).Assembly)
    .Build();

Explicit Registration

var mediator = new MediatorBuilder()
    .RegisterHandlers(() => new List<MessageBinding>
    {
        new MessageBinding(typeof(CreateUserCommand), typeof(CreateUserCommandHandler)),
        new MessageBinding(typeof(GetUserQuery), typeof(GetUserQueryHandler)),
        new MessageBinding(typeof(UserCreatedEvent), typeof(UserCreatedEventHandler))
    })
    .Build();

🔄 Pipeline & Middleware

Mediator.Net supports five types of pipelines for different scenarios:

Pipeline Architecture

Pipeline Types

| Pipeline | Description | Triggers For | |----------|-------------|--------------| | GlobalReceivePipeline | Executes for all messages | Commands, Requests, Events | | CommandReceivePipeline | Executes only for commands | ICommand | | RequestReceivePipeline | Executes only for requests | IRequest | | EventReceivePipeline | Executes only for events | IEvent | | PublishPipeline | Executes when events are published | IEvent (outgoing) |

Creating Custom Middleware

1. Create Middleware Extension

public static class LoggingMiddleware
{
    public static void UseLogging<TContext>(
        this IPipeConfigurator<TContext> configurator, 
        ILogger logger = null)
        where TContext : IContext<IMessage>
    {
        logger ??= configurator.DependencyScope?.Resolve<ILogger>();
        configurator.AddPipeSpecification(new LoggingMiddlewareSpecification<TContext>(logger));
    }
}

2. Create Middleware Specification

public class LoggingMiddlewareSpecification<TContext> : IPipeSpecification<TContext> 
    where TContext : IContext<IMessage>
{
    private readonly ILogger _logger;

    public LoggingMiddlewareSpecification(ILogger logger)
    {
        _logger = logger;
    }

    public bool ShouldExecute(TContext context, CancellationToken cancellationToken) => true;

    public Task BeforeExecute(TContext context, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Processing message: {MessageType}", context.Message.GetType().Name);
        return Task.CompletedTask;
    }

    public Task Execute(TContext context, CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public Task AfterExecute(TContext context, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Completed processing: {MessageType}", context.Message.GetType().Name);
        return Task.CompletedTask;
    }

    public void OnException(Exception ex, TContext context)
    {
        _logger.LogError(ex, "Error processing message: {MessageType}", context.Message.GetType().Name);
        throw ex;
    }
}

Configuring Pipelines

var mediator = new MediatorBuilder()
    .RegisterHandlers(typeof(Program).Assembly)
    .ConfigureGlobalReceivePipe(x => x.UseLogging())
    .ConfigureCommandReceivePipe(x => x.UseValidation())
    .ConfigureRequestPipe(x => x.UseCaching())
    .ConfigureEventReceivePipe(x => x.UseEventStore())
    .ConfigurePublishPipe(x => x.UseOutboxPattern())
    .Build();

🏗️ Depe

Related Skills

View on GitHub
GitHub Stars526
CategoryCustomer
Updated7d ago
Forks52

Languages

C#

Security Score

100/100

Audited on Mar 22, 2026

No findings