QUESTION: Multiple handlers with different response types
See original GitHub issueI’ve seen several other questions about whether or not it is good to have multiple handlers for a single request, but none of them seemed to quite address the use case I’m trying to solve. I have an API that allows for searching a database of geo-located photos. So I have my request class which contains all the available search parameters.
I want to be able to pass the same request to MediatR and get a different type of view model back depending on how the request is sent. For example:
// Request class
public class MyRequest : IRequest<ViewModel1>, IRequest<ViewModel2> {
// search parameters
}
// Handlers
public class Handler1 : IRequestHandler<MyRequest, ViewModel1> {
// handle the request and return ViewModel1
}
public class Handler2 : IRequestHandler<MyRequest, ViewModel2> {
// handle the request and return ViewModel2
}
I could then send the request to the mediator and get the desired response back by using either:
_mediator.Send<ViewModel1>(new MyRequest());
/*-- or --*/
_mediator.Send<ViewModel2>(new MyRequest());
The reason for all this is so I can have 2 endpoints in my API that both accept the same set of search parameters, have the same validation (which I’m handling with a pipeline behavior), but return results positioned slightly differently (mainly to format the location data in different ways).
I tried implementing this, but it doesn’t work. Whichever request is executed first runs fine, but the 2nd one fails because of an invalid cast exception. After some digging, I think I tracked down the issue to the following section of Mediator.cs
:
public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
var requestType = request.GetType();
// I think the error is coming from here. _requestHandlers is static, so the first request is being
// cached as having a response of ViewModel1. Then the 2nd request (with a response of
// ViewModel2) throws an exception because of the different TResponse.
var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));
return handler.Handle(request, cancellationToken, _serviceFactory);
}
So to my question. Is this something that could be supported by MediatR? Or is it a bad idea to structure my code this way?
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
@lilasquared I’m using FluentValidation, so my validation pipeline behavior is setup to be injected with all
IValidator<T>
s for the current request. So because of that, and ASP.NET Core’s DI system not being able to resolve generic types more than 1 level deep, I had to come up with something else.My solution was to make the base validator and pre-processor abstract and generic. That way, the validators and pre-processors for the 2 variants of the request could just inherit the base validator or pre-processor. Like this:
And the same sort of thing for the pre-processors. This fit into my existing validation pipeline behavior and still let me keep the validation/pre-processor logic centralized.
@starx207 if you are using constrained generics for pipeline behaviors you can have the validators handle multiple request types
I’m not sure if that works for the pre-processor.