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

More robust CombinedServiceProvider #4182

Conversation

pblasucci
Copy link
Contributor

This patch adds additional logic to guard against weird edge cases caused by the non-deterministic nature of LInQ + reflection.

Specifically, it adds more logic to a predicate (used by a utility method, Utilities.CombinedServiceProvider.Any) to ensure the correct overload of Enumerable.Any is selected. In a very small -- but impactful! -- percentage of deployments, the order of the MethodInfo instances being processed changes. This change of order, though infrequent, leads to a TargetParameterCountException when the MethodInfo is ultimately invoked. Effectively, all this patch does is make certain assumptions explicit (namely, that we want to use the arity-1 overload rather than a different overload).

This may (or may not) be related to the following issues:

But in any event, this was motivated by having three different services log run-time exceptions with the following stack trace:

System.Reflection.TargetParameterCountException: Parameter count mismatch.
   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at HotChocolate.Utilities.CombinedServiceProvider.Any(Type enumerableType, Object enumerable)
   at HotChocolate.Utilities.CombinedServiceProvider.Concat(Type enumerableType, Object enumerableA, Object enumerableB)
   at HotChocolate.Utilities.CombinedServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at HotChocolate.SchemaBuilder.Setup.InitializeInterceptors[T](IServiceProvider services, IReadOnlyList`1 registered, List`1 interceptors)
   at HotChocolate.SchemaBuilder.Setup.CreateContext(SchemaBuilder builder, LazySchema lazySchema)
   at HotChocolate.SchemaBuilder.Setup.Create(SchemaBuilder builder)
   at HotChocolate.SchemaBuilder.Create()
   at HotChocolate.SchemaBuilder.HotChocolate.ISchemaBuilder.Create()
   at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaAsync(NameString schemaName, RequestExecutorSetup options, IServiceProvider serviceProvider, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaServicesAsync(NameString schemaName, RequestExecutorSetup options, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorNoLockAsync(NameString schemaName, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorAsync(NameString schemaName, CancellationToken cancellationToken)
   at HotChocolate.Execution.RequestExecutorProxy.GetRequestExecutorAsync(CancellationToken cancellationToken)
   at HotChocolate.AspNetCore.HttpPostMiddleware.HandleRequestAsync(HttpContext context, AllowedContentType contentType)
   at HotChocolate.AspNetCore.HttpPostMiddleware.InvokeAsync(HttpContext context)
   at HotChocolate.AspNetCore.WebSocketSubscriptionMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Please note, the patch includes a (skipped) test which simulates the behavior against which the proposed changes will protect. As the actual issue occurs frequently enough to be unavoidable -- but not in a consistent and readily-reproducible fashion -- I hope this is sufficient (in lieu of an actual minimal reproduction).

Also, I am submitting this as a bugfix against the v11 branch, as that is what is currently deployed (we're hopeful for a small point-release in the near future 😉 ). However, I've noticed the v12 branch could also benefit from this patch.

Thanks!

Adds additional logic to guard against weird edge cases caused
by the non-deterministic nature of LInQ + reflection.
@michaelstaib michaelstaib changed the base branch from main-version-11 to main September 6, 2021 06:14
@michaelstaib michaelstaib changed the base branch from main to main-version-11 September 6, 2021 06:15
@michaelstaib
Copy link
Member

/AzurePipelines run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@michaelstaib
Copy link
Member

Thank you for your contribution, I have included your change into 11.3.7

@michaelstaib
Copy link
Member

@pblasucci pblasucci deleted the bugfix/any-parameter-count-mismatch branch September 6, 2021 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants