简体   繁体   中英

GraphQL dotnet core Query class dependency injection

Update: Previous null error was because an empty constructor of Query class with no parameters is created. Now I removed that empty constructor, but get a new Error: System.MissingMethodException: No parameterless constructor defined for type 'App.Controllers.Graphs.Query'


How can you inject your service into the GraphQL Query class? (Schema-first approach)

In my dotnet core 3.1 project, I have installed: GraphQL.Server.Transports.AspNetCore 3.5.0-alpha0046

Here is my root graph:

  public class RootGraph : Schema
  {
    public RootGraph(IServiceProvider provider) : base(provider)
    {
      var schema = For(@"
        type Player {
          _id: ID!
          dbname: String!
          isPremium: Boolean!
          games: [String]!
        }

        input PlayerView {
          dbname: String!
          isPremium: Boolean!
        }

        type Query {
          player(dbname: String!): Player
        }
      ", _ =>
      {
        _.Types.Include<Query>();
      });

      Console.WriteLine(provider); // <-- provider is not null here, everything is good

      Query = schema.Query;
    }
  }

Then I create my Query class like this:

  public class Query
  {
    private readonly ServiceProvider serviceProvider;
    private readonly IPlayerService playerService; 

    public Query( IServiceProvider serviceProvider )
    {
      this.serviceProvider = serviceProvider as ServiceProvider;
      this.playerService = serviceProvider.GetService<IPlayerService>();
    }

    [GraphQLMetadata("player")]
    public async Task<Player> GetPlayer(string dbname)
    {
      Console.WriteLine(serviceProvider);
      Player player = await playerService.Get(dbname);
      return player;
    }
  }

But it's not working. The Query class cannot be created, because I get an exception here:

System.MissingMethodException: No parameterless constructor defined for type 'App.Controllers.Graphs.Query'.\r\n
at System.RuntimeType.CreateInstanceDefaultCtorSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean fillCache)\r\n
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, Boolean wrapExceptions)\r\n
at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)\r\n 
at System.Activator.CreateInstance(Type type)\r\n  
at GraphQL.DefaultServiceProvider.GetService(Type serviceType)\r\n

Part of my Startup.cs :

public void ConfigureServices(IServiceCollection services){

  ...

  // add services
  services.AddSingleton<IPlayerService, PlayerService>();

  // add GraphQL
  services.AddSingleton<RootGraph>();
  services.AddSingleton<Query>();
}

Anyone has an idea on how to provide services to Query class?

You have towrite this code in the startup class.

services.AddScoped<IServiceProvider , ServiceProvider >();

and declare the interface type in the class and pass to constructor.

private readonly IServiceProvider _serviceProvider ;

You can use AddSingleton , AddTransient or AddScoped as per the requirement

So according to this thread , all I need to do is specify the service provider in the schema configuration, like this:

    public RootGraph(IServiceProvider provider) : base(provider)
    {
      var schema = For(@"...", _ =>
      {
        _.Types.Include<Query>();
        _.ServiceProvider = provider; // <=== Add this line here

      });

      // ...

    }

You should be able to inject it directly without having to use the IServiceProvider. Something like this:

[GraphQLMetadata("Query")] 
public class Query
  {
    private readonly IPlayerService playerService; 

    public Query(IPlayerService playerService)
    {
      this.playerService = playerService;
    }

    [GraphQLMetadata("player")]
    public async Task<Player> GetPlayer(string dbname)
    {
      Console.WriteLine(serviceProvider);
      Player player = await playerService.Get(dbname);
      return player;
    }
  }

And then in your SchemaFile you have to add the ServiceProvider to your schema.

  public class RootGraph : Schema
  {
    public RootGraph(IServiceProvider provider) 
        : base(provider)
    {
      var schema = For(@"
        ...
      ", _ =>
      {
        _.Types.Include<Query>();
        _.ServiceProvider = provider;
      });
    }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM