graphql-dotnet/conventions

Incompatible with GraphQL.Server Metrics/Instrumentation

AzureMarker opened this issue · 4 comments

When using GraphQL.Conventions with GraphQL.Server, the following error occurs during the first GraphQL request:

GraphQL Error: Unable to cast object of type 'GraphQL.Instrumentation.InstrumentFieldsMiddleware' to type 'GraphQL.Types.IGraphType'.
   at GraphQL.Conventions.Adapters.GraphTypeAdapter.DeriveTypeFromTypeInfo(Type type)
   at GraphQL.FuncServiceProvider.GetService(Type type) in /_/src/GraphQL/DI/FuncServiceProvider.cs:line 27
   at GraphQL.Types.Schema.System.IServiceProvider.GetService(Type serviceType) in /_/src/GraphQL/Types/Schema.cs:line 107
   at GraphQL.Instrumentation.FieldMiddlewareBuilderExtensions.<>c__DisplayClass3_0.<Use>b__0(ISchema schema, FieldMiddlewareDelegate next) in /_/src/GraphQL/Instrumentation/FieldMiddlewareBuilderExtensions.cs:line 62
   at GraphQL.Instrumentation.FieldMiddlewareBuilder.Build(FieldMiddlewareDelegate start, ISchema schema) in /_/src/GraphQL/Instrumentation/FieldMiddlewareBuilder.cs:line 57
   at GraphQL.Instrumentation.FieldMiddlewareBuilder.ApplyTo(ISchema schema) in /_/src/GraphQL/Instrumentation/FieldMiddlewareBuilder.cs:line 77
   at GraphQL.DocumentExecuter.ExecuteAsync(ExecutionOptions options) in /_/src/GraphQL/Execution/DocumentExecuter.cs:line 74

GraphQL.Server.GraphQLOptions.Metrics is enabled by default. This eventually results in a call to provider.GetService(middleware), where provider.GetService is a reference to GraphTypeAdapter.DeriveTypeFromTypeInfo. This function falls back to Activator.CreateInstance, but casts to IGraphType. This cast causes the above error.

I think I found a workaround by disabling GraphQL.Server's metrics and manually adding InstrumentFieldsMiddleware to the GraphQLEngine via WithMiddleware. I'm not sure this is a good/valid fix though. A proper fix might be to remove the cast since the function is only used as the implementation of GetService, which only requires object? as a return type.

Details: ConfigureServices and Configure methods

Here are my ConfigureServices and Configure methods in Startup (link to file in git repo):

        public void ConfigureServices(IServiceCollection services) {
            // Infer the schema using GraphQL.Conventions
            var engine = new GraphQLEngine()
                .WithQuery<Query>()
                .BuildSchema();
            var schema = engine.GetSchema();

            services.AddControllers();
            services.AddSingleton(schema);
            services.AddWebSockets(_ => { });
            services
                .AddGraphQL((options, provider) => {
                    var logger = provider.GetRequiredService<ILogger<Startup>>();
                    options.UnhandledExceptionDelegate = ctx =>
                        logger.LogError(
                            "GraphQL Error: {Error}\n{Stacktrace}",
                            ctx.OriginalException.Message,
                            ctx.OriginalException.StackTrace
                        );
                })
                .AddWebSockets()
                .AddSystemTextJson();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();
            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
            app.UseWebSockets();
            app.UseGraphQLWebSockets<ISchema>();
            app.UseGraphiQLServer(new GraphiQLOptions { Path = "/graphiql" });
            app.UseGraphQL<ISchema>();
        }

tlil commented

Hey @Mcat12 - apologies for my late response.

Thanks for the above report. It does indeed look like there's a mismatch in return types for DeriveTypeFromTypeInfo(). I've attempted a fix on branch fix/issue-211 (#212). Could you please take it for a spin and see if the changed signature resolves the issue for you? The test suite seems unaffected.

That does seem to fix the error, although I've since changed to the GraphType approach instead of using this library (I think I ran into some issues with passing through GraphQL Server's context; I tested this fix on a previous revision).

tlil commented

No probs. Thanks for checking. 👍

tlil commented

If you recall any context around the other issues that you ran into, feel free to elaborate and I can have a look into it.