Skip to content
Jimmy Bogard edited this page Mar 6, 2014 · 69 revisions

A low-ambition library trying to solve a simple problem - decoupling the in-proc sending of messages from handling messages. Cross-platform, distributed as a portable class library, supporting .NET 4+, Silverlight 5, Windows 8, Windows Phone 8, Xamarin.Android and Xamarin.iOS.

Setting up

Install via NuGet first: Install-Package MediatR

MediatR only has one dependency, Common Service Locator. Any implementation of Common Service Locator is supported with MediatR. You will likely need to install the CSL adaptor for your container of choice.

You'll need to configure two dependencies: first, the mediator itself. StructureMap example: cfg.For<IMediator>().Use<Mediator>(). The other dependency is for the ServiceLocatorProvider delegate from CSL. StructureMap example: cfg.For<ServiceLocatorProvider>().Use(() => ServiceLocator.Current)

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

new Container(cfg => cfg.Scan(scanner => {
    scanner.TheCallingAssembly();
    scanner.AssemblyContainingType<IMediator>();
    scanner.AddAllTypesOf(typeof(IRequestHandler<,>));
    scanner.AddAllTypesOf(typeof(INotificationHandler<>));
});

Basics

MediatR has two kinds of messages it dispatches:

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

Request/response

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 string Handle(Ping request) {
        return "Pong";
    }
}

Finally, send a message through the mediator:

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

In the rare case your message does not require a response, use the base RequestHandler class:

public class OneWay : IRequest { }
public class OneWayHandler : RequestHandler<OneWay> {
    protected override void HandleCore(OneWay request) {
        // Twiddle thumbs
    }
}

Publishing

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 void Handle(Ping notification) {
        Debug.WriteLine("Pong 1");
    }
}
public class Pong2 : INotificationHandler<Ping> {
    public void Handle(Ping notification) {
        Debug.WriteLine("Pong 2");
    }
}

Finally, publish your message via the mediator:

mediator.Publish(new Ping());

Polymorphic dispatch

Handler interfaces are co/contravariant:

public interface IRequestHandler<in TRequest, out TResponse>
    where TRequest : IRequest<TResponse> {
    TResponse Handle(TRequest message);
}
public interface INotificationHandler<in TNotification> {
    void Handle(TNotification notification);
}
public interface IPostRequestHandler<in TRequest, in TResponse> {
    void Handle(TRequest request, TResponse response);
}

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

Post-processing of request/response

In some cases, you might need to have post-processing of a response. You can create a post request handler:

public class PostPingHandler : IPostRequestHandler<Ping, string> {
    public void Handle(Ping request, string response) {
        Debug.WriteLine("Post-processing here.");
    }
}

These can be used to handle side-effects of commands, for example.

Clone this wiki locally