jbogard / MediatR.Extensions.Microsoft.DependencyInjection

MediatR extensions for Microsoft.Extensions.DependencyInjection
MIT License
327 stars 90 forks source link

Error: "Request violates the constrain of type TRequest..." on pipelines #91

Open CheloXL opened 3 years ago

CheloXL commented 3 years ago

I just upgraded MediatR and now my project doesn't works as intented.

I have a request AccessTokenAdminCommand : IRequest<OperationResult<string>>. I also have a pipeline defined as PipelineCommands<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IUserIdDescriptor where TResponse : class

Previously, this was working fine (the pipeline was not trying to intercept my command, since AccessTokenAdminCommand doesn't implements IUserIdDescriptor).

Now, MediatR is trying to run the command through the pipeline, throwing:

System.ArgumentException: GenericArguments[0], 'SpiderWeb.CoreService.App.Commands.Commands.Identity.AccessTokenAdminCommand', on 'SpiderWeb.CoreService.Api.PipelineCommands`2[TRequest,TResponse]' violates the constraint of type 'TRequest'.
 ---> System.TypeLoadException: GenericArguments[0], 'SpiderWeb.CoreService.App.Commands.Commands.Identity.AccessTokenAdminCommand', on 'SpiderWeb.CoreService.Api.PipelineCommands`2[TRequest,TResponse]' violates the constraint of type parameter 'TRequest'.
   at System.RuntimeTypeHandle.Instantiate(Type[] inst)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   --- End of inner exception stack trace ---
   at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c__DisplayClass7_0.<GetCallSite>b__0(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at MediatR.ServiceFactoryExtensions.GetInstances[T](ServiceFactory factory)

I'm opening the issue here since this seems to be a problem with the MS DI and the way you find instances of IPipelineBehavior.

jbogard commented 3 years ago

Unless you're on the latest version of MS DI, this won't work. MS DI only with the latest version supports generic constraints

CheloXL commented 3 years ago

I'm running this on an asp.net core 3.1 app. I'm not directly linking MS DI. Also, this was working fine with the previous version of MediatR (v8)...

jbogard commented 3 years ago

Are you using the vanilla container? MS DI would have choked on this every time up until 5.0, this is highly surprising this worked out-of-the-box. I added the PR to MS DI for this exact scenario.

lilasquared commented 3 years ago

The generic constraints were added for .net 5.0.

It will "work" in previous versions of dotnet core as long as all of your commands sent through the pipeline match the constraint. The moment you try to send a command that violates the constraint you will get this message. Are you sure the exact scenario you are trying worked prior to the MediatR upgrade?

CheloXL commented 3 years ago

Right now I have in front of me a branch of my project with M8 that it is working fine (with the above definitions) and switching to the branch where I upgrade MediatR, I'm getting the above error. So yes, I can confirm that it was working (magically, maybe?) and now it is not.

@jbogard I'm not sure what you mean by vanilla container. I guess the answer is yes, as I'm using the registry container ms provides me in the startup.cs (public void ConfigureServices(IServiceCollection services)).

lilasquared commented 3 years ago

If you can create a minimal repro of the problem I would be happy to check it out. I have my own test project using M8.1 and I get this exception on dotnet core 3.1 when I have two behaviors registered with exclusive constraints.

CheloXL commented 3 years ago

@lilasquared I will try. Please note that I have only one behavior.

Right now I solved this by removing the constraints and checking for the interface implementation inside the handler.

lilasquared commented 3 years ago

@CheloXL sorry yeah, one behavior with exclusive constraints.

in my example I have Ping, and Pong and then PingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : Ping

and I get the exception when I attempt to send Pong. This happens with M8.1 and M9.0 on dotnet core 3.1.