46

I have a .NET Core app where I use the .AddMediatR extension to register the assembly for my commands and handlers following a CQRS approach.

In ConfigureServices in Startup.cs i have used the extension method from the official package MediatR.Extensions.Microsoft.DependencyInjection with the following parameter:

services.AddMediatR(typeof(AddEducationCommand).GetTypeInfo().Assembly);  

The command and commandhandler classes are as follow:

AddEducationCommand.cs

public class AddEducationCommand : IRequest<bool>
{
    [DataMember]
    public int UniversityId { get; set; }

    [DataMember]
    public int FacultyId { get; set; }

    [DataMember]
    public string Name { get; set; }
}

AddEducationCommandHandler.cs

public class AddEducationCommandHandler : IRequestHandler<AddEducationCommand, bool>
    {
        private readonly IUniversityRepository _repository;
        public AddEducationCommandHandler(IUniversityRepository repository)
        {
            _repository = repository;
        }

        public async Task<bool> Handle(AddEducationCommand command, CancellationToken cancellationToken)
        {
            var university = await _repository.GetAsync(command.UniversityId);

            university.Faculties
                .FirstOrDefault(f => f.Id == command.FacultyId)
                .CreateEducation(command.Name);

            return await _repository.UnitOfWork.SaveEntitiesAsync();
        }
    }

When i run the REST endpoint that executes a simple await _mediator.Send(command); code, i get the following error from my log:

Error constructing handler for request of type MediatR.IRequestHandler`2[UniversityService.Application.Commands.AddEducationCommand,System.Boolean]. Register your handlers withthe container. See the samples in GitHub for examples.

I tried to look through the official examples from the docs without any luck. Does anyone know how i configure MediatR to work properly?

starball
  • 20,030
  • 7
  • 43
  • 238
Mike Hawkins
  • 2,144
  • 5
  • 24
  • 42
  • 1
    There are a lot of things outside of what's posted in the question that could go wrong. Please provide [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) so that we could see what you're doing. – Alexander Leonov Jun 09 '18 at 14:34
  • you should go there https://github.com/jbogard/MediatR/blob/master/samples/MediatR.Examples.AspNetCore/Program.cs because there's a lot more code to write in order to register mediatr and its handlers. – hugo Jun 09 '18 at 22:00
  • 7
    Attach a debugger and check the InnerException. Could it be that IUniversityRepository is not registered and therefor the RequestHandler cannot be constructed? services.AddMediatR() is not enough, you also need to register all other dependencies in the services collection. – PeterFromCologne Jun 11 '18 at 10:42
  • Thank you Peter, it was an issue with the configuration of my repository within my Autofac module configuration. – Mike Hawkins Jun 11 '18 at 16:13

17 Answers17

48

I have met the same issue.

The problem is that this line code

services.AddMediatR(typeof(AddEducationCommand).GetTypeInfo().Assembly);

handles all the MediatR IRequest and IRequestHandlers.

but you created an IRepository interface and its implementation class which can't be handled by that MediatR.Extensions.Microsoft.DependencyInjection

so keep all your changes but add this - manually register this like

services.AddScoped(typeof(IUniversityRepository), typeof(UniversitySqlServerRepository));

then issue resolved.

ske
  • 4,694
  • 3
  • 23
  • 35
  • 2
    In my case, the InnerException told me that my dependency couldn't find its own dependency of a specific version (for example, UniversitySqlServerRepository couldn't find Newtonsoft.Json). – Reyhn Mar 03 '20 at 14:43
  • Just want to second that looking at the InnerException is key. My exception was different from @Reyhn's, but it led to the solution. – Rokit Mar 25 '22 at 19:47
20

I went through the same problem and searched for hours but nothing found because this error is a very generic error. Apparently it looks like a MediatR problem but very often, it is NOT the case.

How I went to this conclusion?

To get the original exception, I opened Event Viewer application, which exists by default in windows

In the custom Views > Summary Page Events I found some errors, which corresponded to my application. In my case Errors was something like this:

An error occured during migration

Exception: 
System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
   at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName)
   at Microsoft.EntityFrameworkCore.MySqlDbContextOptionsExtensions.UseMySql(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 mySqlOptionsAction)

As the error says, connectionString was empty. Ultimately I found out that when I was publishing my application to get the dlls, appsettings.json was not in the published folder, due to which connectionString was not found, which is why migration failed. and ultimately, app crashed with a very generic error:

Error constructing handler for request of type MediatR.IRequestHandler. 

Register your handlers with the container. See the samples in GitHub for examples
desertnaut
  • 57,590
  • 26
  • 140
  • 166
SU7
  • 1,586
  • 1
  • 18
  • 26
  • You saved me a lot of time. Thanks you!! How did you add the appsettings.json? – samantha07 Jan 28 '21 at 07:04
  • @samantha07 Thanks for your appreciation :) Due to some mistake, appsettings.json was included in the .gitignore file. Due to it, it wasn't pushed on the bitbucket server, and ultimately when I generated the build from the bitbucket pipeline, the appsettings.json file wasn't there. Had to unignore the file. – SU7 Jan 29 '21 at 13:31
8

For me, none of the other solutions worked unfortunately as I had already registered everything. The solution for me was adding the following line to my program.cs:

.UseDefaultServiceProvider(options => options.ValidateScopes = false);

So the CreateHostBuilder method will be changed to:

Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    }).UseDefaultServiceProvider(options =>
    options.ValidateScopes = false); // needed for mediatr DI

Actually that is something to do with "scoped service", you may find this answer also related.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
7

I had the same problem and in my case when I was registering the dependencies that certain handler needed after I was calling services.AddMediatR() was the actual issue, after I started registering my dependencies before registering Mediator everything works fine.

I'm using dot net core 2.2 with the default DI container and MediatR 6.0.0.

Frankely Diaz
  • 886
  • 1
  • 9
  • 16
4

I solved using this alternative

services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies());
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 28 '22 at 08:24
  • 1
    Many thanks for your answer, It works fine with me, I just needed to add that my .Net Core core version is 3.1 – Mahmoud Nasr Mar 26 '22 at 19:27
3

I had this issue today and my solution and point of note is, if you are going to do this :

services.AddMediatR(Assembly.GetExecutingAssembly());

kindly ensure that the assembly being gotten is the same assembly as your Handlers. In my case, the Handlers were in a different assembly (or project as you may call it).

Chsiom Nwike
  • 484
  • 5
  • 11
3

I am also doing Clean Architecture and CQRS per https://github.com/jasontaylordev/NorthwindTraders

I coded the following:

public class MyClassUpdateCommandHandler : IRequest<MyClass>

but is should have been:

public class MyClassUpdateCommandHandler : IRequestHandler<MyClassUpdateCommand, MyClass>

A more complete example is the following:

  public class MyClassUpdateCommand : IRequest<MyClass>
  {
    public string Id { get; set; }
    ...
    //
    public MyClassUpdateCommand()
    {
      Id = "";
      ...
    }
  }
  //
  public class MyClassUpdateCommandHandler : IRequestHandler<MyClassUpdateCommand, MyClass>
  {
    private ApplicationDbContext _context;
    public MyClassUpdateCommandHandler(ApplicationDbContext context, IMediator mediator)
    {
      _context = context;
    }
    //
    public async Task<MyClass> Handle(MyClassUpdateCommand request, CancellationToken cancellationToken)
    {
      ...
      return _entity;
    }
    //
  }
Phil Huhn
  • 3,307
  • 3
  • 18
  • 35
2

Maybe the issue is that your Handlers are in a separate assembly, if they are, you need to register that assembly name in Startup.cs.

public void ConfigureServices(IServiceCollection services){
    var assembly = AppDomain.CurrentDomain.Load("HandlersDomain");
    services.AddMediatR(assembly);
}

"HandlersDomain" is the name of the assembly where all your Handlers are stored.

Luka Devic
  • 41
  • 2
1

Mine turned out to be a bad name attribute in the controller. It was the word "clients" which was already in the url. Changed the name attribute to "clientlist" and it started working.

1

To solve this problem. We can register manually MediatR for use easily I added Scrutor to my project.

        var serviceConfig = new MediatRServiceConfiguration();
        ServiceRegistrar.AddRequiredServices(services, serviceConfig);

        services.Scan(scan => scan
        .AddTypes(typeof(IRequestHandler<>))
        .AsSelf()
        .WithScopedLifetime()); 

Or without any library

    foreach (var item in GetInstanceByInterface(typeof(IRequestHandler<>)))
    {
            services.AddTransient(item.GetType());
    }

    public IList<object> GetInstanceByInterface(Type baseInterFace)
    {
        var LoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(p => !p.IsDynamic).ToList();
        var result = LoadedAssemblies
            .Where(a => a.FullName.Contains("Ahmad.Aghazadeh")).ToList();

        var baseClassName = baseInterFace.Name;

        return result.SelectMany(a => a.GetTypes())
            .Where(a => a.GetInterfaces().Any(b => b.Name == baseClassName)).Distinct()
            .Select(Activator.CreateInstance).ToList();
    }
Ahmad Aghazadeh
  • 16,571
  • 12
  • 101
  • 98
0

In my case, I had forgotten to register something in my Startup. Like the repository that I was attempting to have implemented via a controller. This was missing in method ConfigureServices of Startup.cs:

 services.AddScoped<IDemoRepository, DemoRepository>();
Adam Cox
  • 3,341
  • 1
  • 36
  • 46
0

In my case the stack trace showed why the problem happened:

System.InvalidOperationException: Error constructing handler for request of type    

MediatR.IRequestHandler`2[XXX.Core.Auth.Refresh.Request,XXXX.Core.Auth.Response]. 

Register your handlers with the container. See the samples in GitHub for examples.

---> MySqlConnector.MySqlException (0x80004005): Access denied for user 'sqluser'@'localhost' (using password: YES)

My database didn't have the user specified in connection string set up. Fixed by adding the user to the database.

Eternal21
  • 4,190
  • 2
  • 48
  • 63
0

I had the same issue with CQRS pattern in .NET Core Web API. What I have done mistakenly is defining the Handler as internal instead of public. Please make sure to define the handler as a public Class.

Chamila Maddumage
  • 3,304
  • 2
  • 32
  • 43
0

I know you did not use ILogger, but if someone using it, encounters this problem, for my case ILogger was the problem.

My QueryHandler was:

public class GetNearbyChargeBoxesQueryHandler : IRequestHandler<GetNearbyChargeBoxesQuery, Response<IEnumerable<GetNearbyChargeBoxesViewModel>>>
        {
            private readonly ILogger _logger;
            private readonly IChargeBoxRepositoryAsync _chargeBoxRepository;
            private readonly IMapper _mapper;

            public GetNearbyChargeBoxesQueryHandler(ILogger logger, IChargeBoxRepositoryAsync chargeBoxRepository, IMapper mapper)
            {
                _logger = logger;
                _chargeBoxRepository = chargeBoxRepository;
                _mapper = mapper;
            }

.....
....
..
.

When I debugged deeper, I noticed something is wrong with the ILogger, then I used ILogger like that ILogger<GetNearbyChargeBoxesQuery> _logger; instead of ILogger _logger;

Looks ridicoulus but that solved my Error constructing handler for request of type MediatR.IRequestHandler....... error.

Baran
  • 362
  • 2
  • 10
0

https://github.com/LeftTwixWand/ModernCQRS

Here I'm showing how to register latest MediatR version via DI container (Autofac)

Also, I added Commands / Queries for CQRS

And added Reqests decorators, and MediatR pipelines:

enter image description here

0

I had forgotten to add IRquestHandler<> to my handler class

public class AddChildCategoriesToPOSHandler : IRequestHandler<AddChildCategoriesToPOSCommand>
EspenHW
  • 61
  • 1
  • 2
-1

You need to inject the dependency of mediator, using .Net 6 I could solve the problem using this in Program.cs:

builder.Services.AddMediatR(typeof(Program).Assembly);
builder.Services.AddScoped<IRequestHandler<CreateProductCommand, Unit>, CreateProductCommandHandler>();
user16217248
  • 3,119
  • 19
  • 19
  • 37