Skip to main content
Version: 2.4.1

MediatR

Overview​

RCommon.MediatR adapts the MediatR library to RCommon's mediator abstraction. It provides:

  • MediatRAdapter — an IMediatorAdapter implementation that delegates Send and Publish calls to MediatR's IMediator.
  • MediatRBuilder — an IMediatRBuilder that wires MediatR into the RCommon service container.
  • Pre-built pipeline behaviors for logging, validation, and unit-of-work.
  • Wrapper types (MediatRRequest, MediatRNotification) that bridge RCommon message contracts to MediatR's internal types.

Application code depends only on IMediatorService from RCommon.Mediator. The MediatR implementation is an infrastructure detail registered at startup.

Installation​

NuGet Package
dotnet add package RCommon.MediatR

This package depends on RCommon.Mediator, RCommon.ApplicationServices, RCommon.Core, RCommon.Persistence, and the MediatR NuGet package. All are pulled in transitively.

Configuration​

Register the MediatR provider inside AddRCommon() using WithMediator<MediatRBuilder>. The configuration delegate is where you register your requests, notifications, and pipeline behaviors.

using RCommon;
using RCommon.Mediator.MediatR;

builder.Services.AddRCommon()
.WithMediator<MediatRBuilder>(mediator =>
{
// Register a fire-and-forget request (no response)
mediator.AddRequest<PlaceOrderRequest, PlaceOrderRequestHandler>();

// Register a request that returns a response
mediator.AddRequest<GetOrderRequest, OrderDto, GetOrderRequestHandler>();

// Register a notification (fan-out to all subscribers)
mediator.AddNotification<OrderPlacedNotification, OrderPlacedNotificationHandler>();
});

Advanced MediatR configuration​

Access the underlying MediatRServiceConfiguration to register handlers from additional assemblies or to set MediatR-specific options:

using System.Reflection;

builder.Services.AddRCommon()
.WithMediator<MediatRBuilder>(mediator =>
{
mediator.AddRequest<PlaceOrderRequest, PlaceOrderRequestHandler>();

mediator.Configure(config =>
{
config.RegisterServicesFromAssemblies(typeof(Program).Assembly);
});
});

Adding pipeline behaviors​

Pipeline behaviors run in registration order before and after every handler. RCommon ships three built-in behaviors:

builder.Services.AddRCommon()
.WithMediator<MediatRBuilder>(mediator =>
{
mediator.AddRequest<PlaceOrderRequest, PlaceOrderRequestHandler>();

// Adds LoggingRequestBehavior and LoggingRequestWithResponseBehavior
mediator.AddLoggingToRequestPipeline();

// Adds ValidatorBehavior and ValidatorBehaviorForMediatR (requires IValidationService)
mediator.AddValidationToRequestPipeline();

// Adds UnitOfWorkRequestBehavior and UnitOfWorkRequestWithResponseBehavior
mediator.AddUnitOfWorkToRequestPipeline();
});

Usage​

Defining requests​

A fire-and-forget request implements IAppRequest:

using RCommon.Mediator.Subscribers;

public class PlaceOrderRequest : IAppRequest
{
public PlaceOrderRequest(Guid customerId, IReadOnlyList<OrderLineDto> lines)
{
CustomerId = customerId;
Lines = lines;
}

public Guid CustomerId { get; }
public IReadOnlyList<OrderLineDto> Lines { get; }
}

A request that returns a response implements IAppRequest<TResponse>:

using RCommon.Mediator.Subscribers;

public class GetOrderRequest : IAppRequest<OrderDto>
{
public GetOrderRequest(Guid orderId)
{
OrderId = orderId;
}

public Guid OrderId { get; }
}

Defining request handlers​

Handle a fire-and-forget request by implementing IAppRequestHandler<TRequest>:

using RCommon.Mediator.Subscribers;

public class PlaceOrderRequestHandler : IAppRequestHandler<PlaceOrderRequest>
{
private readonly IOrderRepository _orders;

public PlaceOrderRequestHandler(IOrderRepository orders)
{
_orders = orders;
}

public async Task HandleAsync(PlaceOrderRequest request, CancellationToken cancellationToken = default)
{
var order = Order.Create(request.CustomerId, request.Lines);
await _orders.AddAsync(order, cancellationToken);
}
}

Handle a request that returns a response by implementing IAppRequestHandler<TRequest, TResponse>:

using RCommon.Mediator.Subscribers;

public class GetOrderRequestHandler : IAppRequestHandler<GetOrderRequest, OrderDto>
{
private readonly IOrderRepository _orders;

public GetOrderRequestHandler(IOrderRepository orders)
{
_orders = orders;
}

public async Task<OrderDto> HandleAsync(GetOrderRequest request, CancellationToken cancellationToken = default)
{
var order = await _orders.GetByIdAsync(request.OrderId, cancellationToken);
return new OrderDto { Id = order.Id, CustomerId = order.CustomerId };
}
}

Defining notifications​

Notifications are broadcast to all registered subscribers. Implement IAppNotification on the notification class:

using RCommon.Mediator.Subscribers;

public class OrderPlacedNotification : IAppNotification
{
public OrderPlacedNotification(Guid orderId, DateTime placedAt)
{
OrderId = orderId;
PlacedAt = placedAt;
}

public Guid OrderId { get; }
public DateTime PlacedAt { get; }
}

Subscribe by implementing ISubscriber<TNotification> from RCommon.EventHandling.Subscribers:

using RCommon.EventHandling.Subscribers;

public class OrderPlacedNotificationHandler : ISubscriber<OrderPlacedNotification>
{
public async Task HandleAsync(OrderPlacedNotification notification, CancellationToken cancellationToken = default)
{
// React to the notification — send email, update read model, etc.
await Task.CompletedTask;
}
}

Sending and publishing​

Inject IMediatorService and use Send or Publish:

using RCommon.Mediator;

public class OrderController : ControllerBase
{
private readonly IMediatorService _mediator;

public OrderController(IMediatorService mediator)
{
_mediator = mediator;
}

[HttpPost]
public async Task<IActionResult> PlaceOrder(PlaceOrderRequest request)
{
// Fire-and-forget: dispatches to a single handler
await _mediator.Send(request);
return Accepted();
}

[HttpGet("{id}")]
public async Task<OrderDto> GetOrder(Guid id)
{
// Request-response: dispatches to a single handler and returns a result
return await _mediator.Send<GetOrderRequest, OrderDto>(new GetOrderRequest(id));
}

[HttpPost("{id}/events")]
public async Task<IActionResult> PublishOrderPlaced(Guid id)
{
// Notification: delivers to all registered subscribers
await _mediator.Publish(new OrderPlacedNotification(id, DateTime.UtcNow));
return NoContent();
}
}

API Summary​

IMediatorService​

MethodDescription
Send<TRequest>(TRequest, CancellationToken)Dispatches a fire-and-forget request to a single handler. Wraps the request in MediatRRequest<TRequest> internally.
Send<TRequest, TResponse>(TRequest, CancellationToken)Dispatches a request to a single handler and returns its response.
Publish<TNotification>(TNotification, CancellationToken)Broadcasts a notification to all registered ISubscriber<TNotification> implementations.

IMediatRBuilder registration methods​

MethodDescription
AddRequest<TRequest, THandler>()Registers a fire-and-forget request and its handler.
AddRequest<TRequest, TResponse, THandler>()Registers a request-response pair and its handler.
AddNotification<TNotification, THandler>()Registers a notification and its subscriber.
AddLoggingToRequestPipeline()Registers LoggingRequestBehavior and LoggingRequestWithResponseBehavior.
AddValidationToRequestPipeline()Registers ValidatorBehavior, ValidatorBehaviorForMediatR, and ValidationService.
AddUnitOfWorkToRequestPipeline()Registers UnitOfWorkRequestBehavior and UnitOfWorkRequestWithResponseBehavior.
Configure(Action<MediatRServiceConfiguration>)Passes a configuration delegate directly to MediatR's AddMediatR.
Configure(MediatRServiceConfiguration)Passes a pre-built configuration instance to MediatR's AddMediatR.

Built-in pipeline behaviors​

BehaviorApplies toDescription
LoggingRequestBehavior<TRequest, TResponse>IRequestLogs request name and payload before and after handler execution.
LoggingRequestWithResponseBehavior<TRequest, TResponse>IRequest<TResponse>Same as above for requests that return a response.
ValidatorBehavior<TRequest, TResponse>IAppRequest<TResponse>Validates IAppRequest<TResponse> instances using IValidationService. Throws on failure.
ValidatorBehaviorForMediatR<TRequest, TResponse>IRequest<TResponse>Validates raw MediatR IRequest<TResponse> instances using IValidationService.
UnitOfWorkRequestBehavior<TRequest, TResponse>IRequestWraps handler execution in a TransactionMode.Default unit of work. Commits on success.
UnitOfWorkRequestWithResponseBehavior<TRequest, TResponse>IRequest<TResponse>Same as above for requests that return a response.

Marker interfaces​

InterfacePackageDescription
IAppRequestRCommon.MediatorMarker for fire-and-forget requests dispatched via Send.
IAppRequest<TResponse>RCommon.MediatorMarker for request-response requests dispatched via Send<TRequest, TResponse>.
IAppNotificationRCommon.MediatorMarker for notifications dispatched via Publish.
IAppRequestHandler<TRequest>RCommon.MediatorHandler for fire-and-forget requests.
IAppRequestHandler<TRequest, TResponse>RCommon.MediatorHandler for request-response requests.
RCommonRCommon