I ran across MediatR the other day while looking into the command pattern. I’ve been working a lot with micro-services. So I wanted to see how I could use the Command Pattern in Web API 2 with MediatR and Ninject.
Project Configuration
From the project wiki, it seems Jimmy Bogard prefers StructureMap as a DI container. I’ve been mostly using Ninject and the documentation wasn’t quite as clear.
Rather than showing the least amount of code, let’s create a new project and send an example command.
Step 1 – Start a New ASP.NET Web Application and make sure Web API is selected.
Step 2 – Installing NuGet Packages
Install the following NuGet packages
- Ninject.Web.WebApi.WebHost
- MediatR
- Swashbuckle
We don’t need Swashbuckle, but it makes it a lot easier to test.
Using MediatR
I’ll show a trivial example that negates the command passed in. Your real world usage will be more complex. But this will show the technology without complicating the example.
Step 1 – Create a IRequest object
Objects that implement the IRequest interface represent Commands. Create a simple class called CommandExample
like:
public class CommandExample : IRequest<bool>
{
public bool NotMe { get; set; }
}
Step 2 – Create a Handler
Handlers should implement IRequestHandler<in TRequest, out TResponse>
. Where TRequest is the type of object we created in step 1 and TResponse is the type you want the handler to return.
So, for us, TRequest is CommandExample
and as we’re negating the bool passed in, TResponse is bool
. So create a new class called CommandExampleHandler
:
public class CommandExampleHandler : IRequestHandler<CommandExample, bool>
{
public bool Handle(CommandExample message)
{
return !message.NotMe;
}
}
And that’s it for the plumbing of MediatR. We have now implemented with command pattern.
But before this will work, we need to configure our DI container, in my case Ninject.
Ninject Configuration
I struggled with this as I couldn’t find any clear examples. The project github repos has an example, but I couldn’t get it to compile . When I finally did, it didn’t work. I failed to use Ninject.Common.Extensions , but the below definitely works.
First, take a copy of https://github.com/jbogard/MediatR/blob/master/samples/MediatR.Examples.Ninject/ContravariantBindingResolver.cs.
Then, in App_Start/NinjectWebCommon.cs
add the following to RegisterServices
kernel.Components.Add<IBindingResolver, ContravariantBindingResolver>();
kernel.Bind<IMediator>().To<Mediator>();
kernel.Bind<IRequestHandler<CommandExample, bool>>().To<CommandExampleHandler>();
kernel.Bind<SingleInstanceFactory>().ToMethod(ctx => t => ctx.Kernel.TryGet(t));
kernel.Bind<MultiInstanceFactory>().ToMethod(ctx => t => ctx.Kernel.GetAll(t));
Note the highlighted line. It is specific to the command and handler classes we created above. Change them for your classes if you’re not following along.
All that’s left is using our commands in our Web API 2 application.
Web API 2 controller
I intend to call mediator from within my controllers. It doesn’t have to be there, but I like to keep thin controllers.
For this example, I updated the ValuesController
. First, create a constructor that takes IMediator
as an argument and sets a field.
private IMediator _mediator;
public ValuesController(IMediator mediator)
{
_mediator = mediator;
}
Then, in my case, I updated the POST action method to
// POST api/values
public async void Post(CommandExample message)
{
response = await _mediator.Send(message);
return;
}
As you can see, we now have a nice thin controller. Note, the use of async and await.
Let’s make sure it works.
Confirming It Works
This is where Swashbuckle comes in handy. Set a breakpoint in the POST action method and press F5. Navigate to http://localhost:<port>/swagger and expand Values and POST. Fill out the message like below
Click “Try it out!” and you should be able to step through the code. Travelling through your handler. And finally back to the controller to see the value passed in negated:
Conclusion
MediatR is a small library, but makes adding the command pattern to your .net projects simple. Getting Ninject working was a little harder than I expected, but nothing too hard. Give it a try and let me know if I’m missing a trick.
Comments Section