graphql-dotnet / server

ASP.NET Core GraphQL Server
MIT License
577 stars 162 forks source link

An exception was thrown while activating GraphQL.Server.Internal.DefaultGraphQLExecuter`1 #247

Closed hungnguyen2505 closed 5 years ago

hungnguyen2505 commented 5 years ago

Hi everyone,

Currently, I'm good to use GraphQL Dotnet with Query and Mutation without Middleware Build-in.

When trying to use build-in middleware of GraphQLDotnet Server I facing this issue in Autofac:

Autofac.Core.DependencyResolutionException: An exception was thrown while activating GraphQL.Server.Internal.DefaultGraphQLExecuter1[[Compass.Service.GraphSchemas.CompassSchema, Compass.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'GraphQL.Server.Internal.DefaultGraphQLExecuter1[Compass.Service.GraphSchemas.CompassSchema]' can be invoked with the available services and parameters: Cannot resolve parameter 'Compass.Service.GraphSchemas.CompassSchema schema' of constructor 'Void .ctor(Compass.Service.GraphSchemas.CompassSchema, GraphQL.IDocumentExecuter, Microsoft.Extensions.Options.IOptions1[GraphQL.Server.GraphQLOptions], System.Collections.Generic.IEnumerable1[GraphQL.Execution.IDocumentExecutionListener], System.Collections.Generic.IEnumerable1[GraphQL.Validation.IValidationRule])'. at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 160 at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 120 at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 118 --- End of inner exception stack trace --- at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 136 at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 85 at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 130 at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 83 at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable1 parameters, Object& instance) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 1041 at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 871 at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at GraphQL.Server.Transports.AspNetCore.GraphQLHttpMiddleware1.InvokeAsync(HttpContext context) at GraphQL.Server.Transports.WebSockets.GraphQLWebSocketsMiddleware`1.InvokeAsync(HttpContext context) at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.InvokeCore(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Or Microsoft dependency

System.InvalidOperationException: Unable to resolve service for type 'Compass.Service.GraphSchemas.CompassSchema' while attempting to activate 'GraphQL.Server.Internal.DefaultGraphQLExecuter1[Compass.Service.GraphSchemas.CompassSchema]'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType) at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at GraphQL.Server.Transports.AspNetCore.GraphQLHttpMiddleware1.InvokeAsync(HttpContext context) at GraphQL.Server.Transports.WebSockets.GraphQLWebSocketsMiddleware`1.InvokeAsync(HttpContext context) at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.InvokeCore(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I don't know what I missing to use with the build-in middle ware:

Here is what I registered for GraphQL:

           services.AddSingleton<IDependencyResolver>(x =>
                new FuncDependencyResolver(type =>
                x.GetRequiredService(type)));

            services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
            services.AddSingleton<IDocumentWriter, DocumentWriter>();
            services.AddSingleton<ISchema, CompassSchema>();
            services.AddSingleton<CompassQuery>();
            services.AddSingleton<CompassMutation>();
            services.AddSingleton<CompassSubscription>();
            services.AddSingleton<InvestmentType>();

            services.AddGraphQL(options =>
            {
                options.EnableMetrics = true;
                options.ExposeExceptions = true;
            })
            .AddUserContextBuilder(context =>
            {
                return new GraphQLUserContext { User = context.User };
            })
            .AddWebSockets()
            .AddDataLoader();
            return services;
            app.UseWebSockets();

            app.UseGraphQLWebSockets<CompassSchema>("/compassapi/api/graphql");

            //app.UseMiddleware<GraphQLMiddleware>(settings); If I use this one the GraphQL can work for mutation and query but I cannot use subscriptions

            app.UseGraphQL<CompassSchema>("/compassapi/api/graphql");

            app.UseGraphQLPlayground(new GraphQLPlaygroundOptions()
            {
                Path = "/ui/playground",
                GraphQLEndPoint = "/compassapi/api/graphql"
            });
            app.UseGraphiQLServer(new GraphiQLOptions
            {
                GraphiQLPath = "/ui/graphiql",
                GraphQLEndPoint = "/compassapi/api/graphql"
            });
            app.UseGraphQLVoyager(new GraphQLVoyagerOptions()
            {
                Path = "/ui/voyager",
                GraphQLEndPoint = "/compassapi/api/graphql",
            });

If I do not use the middleware build-in the GraphQL can work for mutation and query but I cannot use subscriptions.

Does anyone have any suggestion what I am missing in the config?

Here is the constructor of the schema query and subscription

public class CompassSchema : Schema
    {
        public CompassSchema(IDependencyResolver resolver) : base(resolver)
        {
            Query = resolver.Resolve<CompassQuery>();
            Mutation = resolver.Resolve<CompassMutation>();
            Subscription = resolver.Resolve<CompassSubscription>();
        }
    }
 public class CompassQuery : ObjectGraphType<object>
    {
        public CompassQuery(IInvestmentService investmentService)
        {
            Name = "CompassQuery";

            Field<PaginatedInvestmentType>("investments",
                arguments: new QueryArguments(
                    new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "pageSize", Description = "size of the list returned" },
                    new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "pageNumber", Description = "page of the list" },
                    new QueryArgument<StringGraphType> { Name = "orderBy", Description = "order by column" },
                    new QueryArgument<BooleanGraphType> { Name = "isOrderAsc", Description = "is order by" },
                    new QueryArgument<StringGraphType> { Name = "name", Description = "filter by name" },
                    new QueryArgument<BooleanGraphType> { Name = "includeIsDeleted", Description = "is include the deleted records" },
                    new QueryArgument<BooleanGraphType> { Name = "isPaging", Description = "is paging the records" },
                    new QueryArgument<ListGraphType<IdGraphType>> { Name = "refStrategyIds", Description = "filter by refStrategyIds" },
                    new QueryArgument<ListGraphType<StringGraphType>> { Name = "investmentStatuses", Description = "List Statuses of Investment" }),
                resolve: context =>
                {
                    var searchInput = new SearchInvestmentViewModel()
                    {
                        PageSize = context.GetArgument<int>("pageSize"),
                        PageNumber = context.GetArgument<int>("pageNumber"),
                        OrderBy = context.GetArgument<string>("orderBy"),
                        IsOrderAsc = context.GetArgument<bool>("isOrderAsc"),
                        Name = context.GetArgument<string>("name"),
                        IncludeIsDeleted = context.GetArgument<bool?>("includeIsDeleted"),
                        IsPaging = context.GetArgument<bool?>("isPaging"),
                        InvestmentStatuses = context.GetArgument<List<string>>("investmentStatuses"),
                        RefStrategyIds = context.GetArgument<List<Guid?>>("refStrategyIds"),
                    };

                    return investmentService.SearchAsync(searchInput);
                }
            );
}

Subscription

 public class CompassSubscription : ObjectGraphType<object>
    {
        private readonly IInvestmentEventService _investmentEventService;
        public CompassSubscription(IInvestmentEventService investmentEventService)
        {
            _investmentEventService = investmentEventService;
            Name = "CompassSubscription";
            AddField(new EventStreamFieldType
            {
                Name = "investmentEvent",
                Type = typeof(InvestmentEventType),
                Resolver = new FuncFieldResolver<InvestmentEventViewModel>(ResolveEvent),
                Subscriber = new EventStreamResolver<InvestmentEventViewModel>(Subscribe)
            });
        }
}

The reason I am switching to the build-in middle ware to able use the subscription via websockets. Thank u,

dharmeshtailor commented 5 years ago

Hi, This what we have :

services.AddGraphQL().AddWebSockets().AddDataLoader();

Autofac for DI:

builder.RegisterType<PrincipalListener>().AsImplementedInterfaces();
builder.RegisterType<HttpContextAccessor>().AsImplementedInterfaces();
builder.Register<DocumentWriter>(c => new DocumentWriter(false)).AsImplementedInterfaces().SingleInstance();
builder.RegisterType<DocumentExecuter>().AsImplementedInterfaces().SingleInstance();
builder.Register<GraphQLSchema>(c =>
{
    var cc = c.Resolve<IComponentContext>();
    var dependencyResolver = new FuncDependencyResolver(type => cc.Resolve(type));
    return new GraphQLSchema(dependencyResolver);
}).AsSelf().AsImplementedInterfaces().SingleInstance();

HttpContextAccessor is required in PrincipalListener to assign Context User to WebSockets properties.

Then:

app.UseMiddleware<NtlmAndAnonymousSetupMiddleware>();
app.UseWebSockets();
app.UseGraphQLWebSockets<GraphQLSchema>("/api/graphql");

We have Specific controller named GraphQLController, where all requests are posted instead of using inbuilt middleware.

I remember I had same error as you, but cannot remember what I did to fix it. :-(

Hope this helps.

piotrbulkowski commented 4 years ago

Had the same problem, earlier I've tried to do containerBuilder.RegisterType<MachShopSchema>().As<ISchema>().InstancePerRequest(); but specifying it as a singleton with directly provided IDependencyResolver fixed it

containerBuilder.Register(c =>
{
    var cc = c.Resolve<IComponentContext>();
    var dependencyResolver = new FuncDependencyResolver(type => cc.Resolve(type));
    return new MachShopSchema(dependencyResolver);
}).AsSelf().AsImplementedInterfaces().SingleInstance();