Jimmy Bogard edited this page Jun 5, 2018 · 35 revisions

A low-ambition library trying to solve a simple problem - decoupling the in-proc sending of messages from handling messages. Cross-platform, supporting .NET 4.5, netstandard1.3, and netstandard2.0.

Setting up

Install via NuGet first: Install-Package MediatR

MediatR has no dependencies. You will need to configure a single factory delegate, used to instantiate all handlers, pipeline behaviors, and pre/post-processors.

You'll need to configure two dependencies: first, the mediator itself. StructureMap example: cfg.For<IMediator>().Use<Mediator>(). The other dependency is the factory delegate, ServiceFactory. The Mediator class is defined as:

public class Mediator : IMediator
    public Mediator(
        ServiceFactory serviceFactory)

The factory delegates are named delegates around a couple of generic factory methods:

public delegate object ServiceFactory(Type serviceType);

StructureMap example: cfg.For<ServiceFactory>().Use<ServiceFactory>(ctx => ctx.GetInstance);. This factory delegate is how MediatR builds instances of the request and notification handlers.

Finally, you'll need to register your handlers in your container of choice. StructureMap example:

new Container(cfg => cfg.Scan(scanner => {

Declare whatever flavor of handler you need - sync, async or cancellable async. From the IMediator side, the interface is async-only, designed for modern hosts.


The full StructureMap example looks like:

var container = new Container(cfg =>
    cfg.Scan(scanner =>
        scanner.AssemblyContainingType<Ping>(); // Our assembly with requests & handlers
    cfg.For<ServiceFactory>().Use<ServiceFactory>(ctx => ctx.GetInstance);


The full Autofac example looks like:

// uncomment to enable polymorphic dispatching of requests, but note that
// this will conflict with generic pipeline behaviors
// builder.RegisterSource(new ContravariantRegistrationSource());

// mediator itself

// request handlers
  .Register<SingleInstanceFactory>(ctx => {
    var c = ctx.Resolve<IComponentContext>();
    return t => c.TryResolve(t, out var o) ? o : null;

// notification handlers
  .Register<MultiInstanceFactory>(ctx => {
    var c = ctx.Resolve<IComponentContext>();
    return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));

// finally register our custom code (individually, or via assembly scanning)
// - requests & handlers as transient, i.e. InstancePerDependency()
// - pre/post-processors as scoped/per-request, i.e. InstancePerLifetimeScope()
// - behaviors as transient, i.e. InstancePerDependency()
builder.RegisterAssemblyTypes(typeof(MyType).GetTypeInfo().Assembly).AsImplementedInterfaces(); // via assembly scan
//builder.RegisterType<MyHandler>().AsImplementedInterfaces().InstancePerDependency();          // or individually


If you're using ASP.NET Core then you can skip the above configuration and use MediatR's MediatR.Extensions.Microsoft.DependencyInjection package which includes a IServiceCollection.AddMediatR(Assembly) extension method, allowing you to register all Handlers and Pre/PostProcessors in a given assembly.


For more examples, check out the samples for working examples using:

  • Autofac
  • LightInject
  • Castle Windsor
  • DryIoc
  • Ninject
  • Simple Injector
  • StructureMap
  • Lamar
  • Unity

These examples highlight all the features of MediatR including sync/async, request/response, pub/sub and more.


MediatR has two kinds of messages it dispatches:

  • Request/response messages, dispatched to a single handler
  • Notification messages, dispatched to multiple handlers


The request/response interface handles both command and query scenarios. First, create a message:

public class Ping : IRequest<string> { }

Next, create handler:

public class PingHandler : IRequestHandler<Ping, string> {
    public Task<string> Handle(Ping request, CancellationToken cancellationToken) {
        return Task.FromResult("Pong");

Finally, send a message through the mediator:

var response = await mediator.Send(new Ping());
Debug.WriteLine(response); // "Pong"

In the case your message does not require a response, use the AsyncRequestHandler<TRequest> base class:

public class OneWay : IRequest { }
public class OneWayHandlerWithBaseClass : AsyncRequestHandler<OneWay> {
    protected override Task Handle(OneWay request, CancellationToken cancellationToken) {
        // Twiddle thumbs

Or if the request is completely synchronous, inherit from the base RequestHandler class:

public class SyncHandler : RequestHandler<Ping, string> {
    protected override string Handle(Ping request) {
        return "Pong";

Request types

There are two flavors of requests in MediatR - ones that return a value, and ones that do not:

  • IRequest<T> - the request returns a value
  • IRequest - the request does not return a value

To simplify the execution pipeline, IRequest inherits IRequest<Unit> where Unit represents a terminal/ignored return type.

Each request type has its own handler interface, as well as some helper base classes:

  • IRequestHandler<T, U> - implement this and return Task<U>
  • RequestHandler<T, U> - inherit this and return U

Then for requests without return values:

  • IRequestHandler<T> - implement this and you will return Task<Unit>.
  • AsyncRequestHandler<T> - inherit this and you will return Task.
  • RequestHandler<T> - inherit this and you will return nothing (void).


For notifications, first create your notification message:

public class Ping : INotification { }

Next, create zero or more handlers for your notification:

public class Pong1 : INotificationHandler<Ping> {
    public Task Handle(Ping notification, CancellationToken cancellationToken) {
        Debug.WriteLine("Pong 1");
        return Task.CompletedTask;
public class Pong2 : INotificationHandler<Ping> {
    public Task Handle(Ping notification, CancellationToken cancellationToken) {
        Debug.WriteLine("Pong 2");
        return Task.CompletedTask;

Finally, publish your message via the mediator:

await mediator.Publish(new Ping());

Polymorphic dispatch

Handler interfaces are contravariant:

public interface IRequestHandler<in TRequest, TResponse>
    where TRequest : IRequest<TResponse> {
    Task<TResponse> Handle(TRequest message, CancellationToken cancellationToken);
public interface INotificationHandler<in TNotification> {
    Task Handle(TNotification notification, CancellationToken cancellationToken);

Containers that support generic variance will dispatch accordingly. For example, you can have an INotificationHandler<INotification> to handle all notifications.


Send/publish are async from the IMediator side, with corresponding sync and async-based interfaces/base classes for requests/responses/notification handlers.

Your handlers can use the async/await keywords as long as the work is awaitable:

public class PingHandler : IRequestHandler<Ping, Pong> {
    public async Task<Pong> Handle(Ping request, CancellationToken cancellationToken) {
        await DoPong(); // Whatever DoPong does

You will also need to register these handlers with your container of your choice, similar to the synchronous handlers shown above.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.