MediatR with ASP.NET Core DI
Asked Answered
W

6

40

I'm playing around with the new ASP.NET Core and are currently creating a API that I want to call from a JavaScript frontend.

I want to use the mediator pattern to reduce the coupling, and I have found the Library MediatR from Jimmy Bogard.

My problem consist in wiring it up using the build in DI, I have tried looking at the examples, but can't see to crack how it binds into the ConfigureServices method in the startup class.

Do anybody have any insight?

UPDATE: I got it working, from my ConfigureService method:

services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));

services.Scan(scan => scan
        .FromAssembliesOf(typeof(IMediator), typeof(MyHandler.Handler))
        .AddClasses()
        .AsImplementedInterfaces());
Whomsoever answered 15/2, 2016 at 12:55 Comment(5)
github.com/jbogard/MediatR/blob/master/samples/… Seems pretty simple to me, but for assembly scan you need this Scrutor package (ASP.NET Core's DI doesn't come with assembly scanning and there are no plans to ship it)Thimble
How would you add that to the ConfigureService method? services.AddTransient(typeof (IMediator), BuildMediator().GetType());Whomsoever
You don't want to register it that way, Transient means that it will be created every time when the dependency is resolved. services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t)); and services.AddScoped<MultiInstanceFactory>(p => t => p.GetRequiredServices(t)); are factory methods that are injected into mediator and resolve the notifications (multi) or requests (single)Thimble
The IMediator itself you can register as services.AddScoped<IMediator,Mediator>() as it has public constructor and the delegates are registered in previous step. In the example the last one is did automatically via Scrutor scanningThimble
@Thimble Does my own answer match how you would do it?Whomsoever
G
81

For the latest MediatR version 12.x February 2023:

As of version 12, Mediatr offers support for registering Handlers with the Microsoft Dependency Injection framework directly within the Mediatr namespace, and so can be achieved when calling AddMediatR on the Service collection.

services.AddMediatR(cfg =>
     cfg.RegisterServicesFromAssembly(typeof(Ping).Assembly));

Where Ping is a type that is contained in an assembly that should be scanned to register Handlers, etc.

Note: The additional NuGet package (described below) that had been created to support such Registration in previous versions of MediatR is no longer required; details of this, and other breaking changes can be found at the Migration Guide on GitHub:

For earlier Mediatr versions up to and including 11.x:

In July 2016, Jimmy Bogard, author of MediatR, had released a package to register MediatR, and Handlers, with the ASP.Net Core DI service (which is actually the interface IServiceCollection, implemented in Microsoft.Extensions.DependencyInjection and which is not restricted to use solely within ASP.Net Core).

MediatR.Extensions.Microsoft.DependencyInjection

Link to GitHub Project.

Link to NuGet Package information.

A blog post introducing the package and it's capabilities can be found here

Example registration copied directly from the (very short) blog post:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();

  services.AddMediatR(typeof(Startup));
}

This package performs several functions to enable MediatR, including the required scanning of assemblies for Handlers:

You can either pass in the assemblies where your handlers are, or you can pass in Type objects from assemblies where those handlers reside. The extension will add the IMediator interface to your services, all handlers, and the correct delegate factories to load up handlers.

Note: This package is no longer required as of Mediatr version 12.

For all versions

Once the dependency registration has been specified using the relevant method described above, within your controllers, you can just use an IMediator dependency:

public class HomeController : Controller
{
  private readonly IMediator _mediator;

  public HomeController(IMediator mediator)
  {
    _mediator = mediator;
  }
  public IActionResult Index()
  {
    var pong = _mediator.Send(new Ping {Value = "Ping"});
    return View(pong);
  }
}
Grandee answered 17/9, 2016 at 22:56 Comment(3)
This should be the correct answer. Not only is it more elegant and simple, but it's the one recommended by the creator of Mediatr.Devilish
Seems that starting from v12 of MediatR, MediatR.Extensions.Microsoft.DependencyInjection is deprecatedMosstrooper
@Mosstrooper I have updated my answer to bring it up to date for the deprecation of the package as per MediatR version 12.Grandee
C
6

There´s a good tutorial by https://dotnetcoretutorials.com/. This's the example code for the correct installation and configuration of MediatR.

Installing MediatR

The first thing we need to do is install the MediatR nuget package. So from your package manager console run :

Install-Package MediatR

We also need to install a package that allows us to use the inbuilt IOC container in .NET Core to our advantage (We’ll see more of that shortly). So also install the following package :

Install-Package MediatR.Extensions.Microsoft.DependencyInjection

Finally we open up our startup.cs file. In our ConfigureServices method, we need to add in a call to register all of MediatR’s dependencies.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMediatR(Assembly.GetExecutingAssembly());
    //Other injected services. 
}

This is the link: https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-part-3-mediatr-library/

I hope this helps.

Caulicle answered 25/11, 2019 at 15:44 Comment(0)
D
5

Accroding to MediatR documentation to register MediatR service and all handlers you should use AddMediatR method in this way:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();

  services.AddMediatR(typeof(Startup));
}

It's easy , it's comfortable but what if you want to replace one of the handlers? Then you should find old in one of yours .cs files and remove interface from it so there will be no conflict in ID for more then one implementation.

To avoid this, my advice is to register every handler manually

     public void ConfigureServices(IServiceCollection services)
    {
      services.AddMvc();
    
      services.AddMediatR(typeof(Mediator)); //registering MediatR and all required dependencies
      //registering handlers
      services.AddScoped<IRequestHandler<CreateProductCommand, int>,CreateProductCommandHandler>(); 
      services.AddScoped<IRequestHandler<DeleteProductCommand, int>,DeleteProductCommandHandler>();     

    }

This solution allow you to have multiply handler implementation for the same command and give a control of witch implementation is used

Donate answered 14/2, 2022 at 9:11 Comment(0)
W
4

I got it working, my code:

public void ConfigureServices(IServiceCollection services)
{
      services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));
      services.AddScoped<MultiInstanceFactory>(p => t => p.GetRequiredServices(t));
      services.Scan(scan => scan
              .FromAssembliesOf(typeof(IMediator), typeof(MyHandlerOne.Handler))
              .FromAssembliesOf(typeof(IMediator), typeof(MyHandlerTwo.Handler))
             .AddClasses()
             .AsImplementedInterfaces());
}

and I have a class that implements the GetRequiredService that MultiInstanceFactory need:

public static class GetServices
{
    public static IEnumerable<object> GetRequiredServices(this IServiceProvider provider, Type serviceType)
    {
        return (IEnumerable<object>)provider.GetRequiredService(typeof(IEnumerable<>).MakeGenericType(serviceType));
    }
}
Whomsoever answered 15/2, 2016 at 13:56 Comment(0)
G
0

I created a DI helper for ASP.NET Core RC2 that you can add to your startup. It gives you basic convention based mapping so if you have a class like:

MyClass : IMyClass

It will map IMyClass in the IOC container which will make it available for injection.

I also added the Mappings for MediatR.

To use it Just add the class to your project and then in your startup.cs class add the lines you need to the ConfigureServices() method:

public void ConfigureServices(IServiceCollection services)
{
    //Other Code here......

    var ioc = new PearIoc(services);

    //ioc.AddTransient<IEmailSender, AuthMessageSender>();
    //ioc.AddTransient<ISmsSender, AuthMessageSender>();

    ioc.WithStandardConvention();
    ioc.WithMediatR();
    ioc.RunConfigurations();
}

I added the AddTransient() method just for convenience (you could also just use services.AddTransient()) but it also exposes the IServiceCollection in case you need to do more with it.

You can also extend it like I did with the .WithMediatR() extension and write your own custom mappings.

Glynda answered 7/6, 2016 at 17:28 Comment(0)
F
0

Another way to register all commands

public void ConfigureServices(IServiceCollection services)
{
    services.AddMediatR(Assembly.GetAssembly(typeof(YouClass)));
}
Forebrain answered 25/9, 2022 at 1:16 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.