Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue: "No service for type 'MediatR.IRequestHandler'" #1092

Open
AlbertoVPersonal opened this issue Jan 8, 2025 · 4 comments
Open

Issue: "No service for type 'MediatR.IRequestHandler'" #1092

AlbertoVPersonal opened this issue Jan 8, 2025 · 4 comments

Comments

@AlbertoVPersonal
Copy link

Environment

  • Windows 11 Pro
  • .NET8
  • MediatR 12.4.1
  • Console app
  • All classes are in the same assembly

Issue description

I want to use generic handlers with notifications. Due to I was not able to do it, I have changed to generic requests.
And now I'm getting the below error message.

Issue error message

System.InvalidOperationException: No service for type 'MediatR.IRequestHandler`1[NotificationsMediatR.Notifications.GenericBasicTypeNotification`1[System.String]]' has been registered.

Source code

Handlers

public class LocalMediatR
{
    private static LocalMediatR _instance;

    private IMediator _mediator;

    // ...
}

public class HandlerBaseProperties {
  // ...
}

public class BaseNotification : IRequest {
 // ...
}

internal class GenericBasicTypeNotification<T> : BaseNotification { 
 // ...
}

internal class GenericBaseTypeNoResponseHandler<T> : HandlerBaseProperties, IRequestHandler<GenericBasicTypeNotification<T>>
{
    public async Task Handle(GenericBasicTypeNotification<T> request, CancellationToken cancellationToken) {
       // ...
   }
}

Configure services

//...

// Inject MediatR
services.AddMediatR(cfg => {
    cfg.MaxTypesClosing = 0;
    cfg.RegisterGenericHandlers = true;
    cfg.RegisterServicesFromAssembly(typeof(Startup).Assembly);
});

services.AddSingleton<IMediator, Mediator>();
services.AddTransient<BaseWithoutResponseTopicHandler>();
services.AddTransient(typeof(GenericBaseTypeNoResponseHandler<>));
services.AddTransient<GenericBaseTypeNoResponseHandler<string>>(); // Theoretically it is not needed

//...

Configure method

// set the mediatR
var mediatR = LocalMediatR.GetInstance();
mediatR.SetMediatR(mediator);

Example of use and it generates the error

var notif = new GenericBasicTypeNotification<string>()
{
    Payload = "my value"
};
await LocalMediatR.GetInstance().Mediator.Send(notif);

other links read and tests performed

@zachpainter77
Copy link
Contributor

zachpainter77 commented Jan 15, 2025

I'm guessing that your handlers are in a different assembly than your requests. If that is the case then you just need to add both assemblies in the AddMediatR configuration options.

Also, the types you are passing as generic type parameters must also be available during the registration of mediatR so you'll also need to include those assemblies as well.

Also the internal access modifiers on your handler and requests might also be causing some issues.

@zachpainter77
Copy link
Contributor

zachpainter77 commented Jan 15, 2025

namespace Assembly1{
   public class MyDto{
   }
}
namespace Assembly2{
    public class GenericBasicTypeNotification<T> : BaseNotification { 
     // ...
    }
}
namespace Assembly3{
    public class GenericBaseTypeNoResponseHandler<T> : HandlerBaseProperties, RequestHandler<GenericBasicTypeNotification<T>>
    {
        public async Task Handle(GenericBasicTypeNotification<T> request, CancellationToken cancellationToken) {
           // ...
        }
     }
}

//AddMediatR method
services.AddMediatR(cfg => {   
    cfg.RegisterGenericHandlers = true;
    cfg.RegisterServicesFromAssemblies([typeof(MyDto).Assmebly, typeof(GenericBasicTypeNotification<>).Assembly, typeof(GenericBaseTypeNoResponseHandler<>).Assembly]);
});

//remember all assemblies need to be included so that they are available to scan during AddMediatR registration.

@zachpainter77
Copy link
Contributor

zachpainter77 commented Jan 15, 2025

Ok so this specific issue is also caused by the fact that the auto registration only scans the assemblies you provide. Your assemblies do not define the primitive types so you'll need to add them.

builder.Services.AddMediatR(cfg =>
{
    //add this to disable the constraint on number of types that can close.
    cfg.MaxTypesClosing = 0; 
    //enable generic handlers                   
    cfg.RegisterGenericHandlers = true;    
    //add typeof(int).Assembly to include primitive types in assembly scanning.
    cfg.RegisterServicesFromAssemblies([typeof(Startup).Assembly, typeof(int).Assembly]); 
});

Request / Handler Definition ->

using MediatR;

namespace TestApplication
{      
    public class GenericRequest<T> : IRequest<T>
    {
        public T Payload { get; set; }
    }


    public class GenericHandler<T> : IRequestHandler<GenericRequest<T>, T>
    {
        public Task<T> Handle(GenericRequest<T> request, CancellationToken cancellationToken)
        {
            return Task.FromResult(request.Payload);
        }
    }
}

MVC controller ->

using MediatR;
using Microsoft.AspNetCore.Mvc;
using TestApplication;

namespace TestMediatRMVC.Controllers
{
    public class HomeController : Controller
    {
      
        private readonly IMediator _mediator;

        public HomeController(IMediator mediator)
        {
            _mediator = mediator;
        }

        public async Task<IActionResult> Index()
        {
            var request = new GenericRequest<string>
            {
                Payload = "Hello World!"
            };
            var result = await _mediator.Send(request);
            ViewBag.Result = result;
            return View();
        }
    }
}

Razor view ->

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<p>@ViewBag.Result</p>

browser view ->
image

This should fix your issue. Cheers!

@AlbertoVPersonal
Copy link
Author

Thanks for your comments. I will test it. Last week I have been very busy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants