MediatR
MediatR copied to clipboard
Handler not found
I'm trying to register a generic request handler for a generic request, but I'm getting the error below when calling
await _mediator.Send(new ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>());
System.InvalidOperationException: Handler was not found for request of type MediatR.IRequestHandler2[MyNamespace.ExchangeOrderRequest
1[MyNamespace.ExchangeOrderResponseSuccessEvent],MediatR.Unit]. Register your handlers with the container. See the samples in GitHub for examples.
As side note, for giggles, I was able to inject an instance of IRequestHandler<ExchangeOrderRequest< ExchangeOrderResponseSuccessEvent>> into a controller just fine.
// Some assembly scanning, doesn't find my handler
services.AddMediatR(typeof(Startup), typeof(ExchangeOrderRequest), typeof(IDocumentMessage), typeof(OrderExecution.Handler));
// Try to manually add the handler. Still doesn't find it
services.AddTransient<IRequestHandler<ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>>, ExchargeOrderRequestHandler<ExchangeOrderResponseSuccessEvent, ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>>>();
public class ExchargeOrderRequestHandler<TEvent, TRequest> : IRequestHandler<TRequest>
where TRequest : ExchangeOrderRequest<TEvent>
where TEvent : ExchangeOrderEvent
{
// Stuff
}`
public class ExchangeOrderRequest<T>: DocumentMessage, IRequest where T: ExchangeOrderEvent
{
// Stuff
}
public class ExchangeOrderEvent : IEvent
{
// Stuff
}
What am I missing here?
can you post a small repo that reproduces this? I know that constrained generics are not supported by the dotnet core DI but if you're registering them manually i'm not sure why it wouldn't work. It could be that you have to create a non-generic class and register that. Like:
public class ExchangeOrderSuccessHandler : ExchangeOrderRequestHandler<ExchangeOrderSuccessEvent, ExchangeOrderRequest<ExchangeOrderSuccessEvent>> { ... }
@lilasquared Done: https://github.com/darthg8r/GenericMediatorHandler
It can't be the DI container though. I mentioned above:
As side note, for giggles, I was able to inject an instance of IRequestHandler<ExchangeOrderRequest< ExchangeOrderResponseSuccessEvent>> into a controller just fine.
It looks like there's something off in the handler resolution. Explicitly adding Unit as a generic argument to the request handler seems to have fixed it..
services.AddTransient<IRequestHandler<ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>, Unit>, ExchargeOrderRequestHandler<ExchangeOrderResponseSuccessEvent, ExchangeOrderRequest<ExchangeOrderResponseSuccessEvent>>>();
public class ExchargeOrderRequestHandler<TEvent, TRequest> : IRequestHandler<TRequest, Unit>
where TRequest : ExchangeOrderRequest<TEvent>
where TEvent : ExchangeOrderEvent
{
// Stuff
}
If I have some time, I'll see if I can find the actual bug in the library. Change to fix the problem can be seen in final commit in my repo.
Looks like you don't even need Unit
in the class definition, just in the registration. I think this is the same issue I mentioned above where dotnet core DI doesn't support generic registrations. When you use the IRequestHandler<T>
interface I don't think the DI can properly map it to IRequestHandler<T, Unit>
. I don't know for sure but thats my guess. If you use Lamar or another more mature DI you most likely won't have this problem.
Hey there, my team and I are having the same problem due to the DI container of .NET. Is there any chance that this problem would be addressed somewhere?
#635
I have a similar issue... I was able to solve it by using the AutoFac container but couldn't get it to work using the default container.
I have the same issue. Will it be solved?
Use a different container, the Microsoft DI container often can't handle these edge cases, and this is one of them. It can't handle partially closed generic types.
Otherwise, it might be fixed in the registration side of things, we might be able to forward registrations perhaps?
I use Ninject in a .Net 4.8 project and IRequestHandler<,> can't be resolved through the ContravariantBindingResolver based on MediatR.Examples.Ninject. Could it also be the container in fault?