Dependency Injection

Tanka GraphQL servers is built on top of the ASP.NET Core and uses the builtin dependency injection services.

The recommended lifetime of a schema in Tanka is singleton as long as the schema does not change. This adds a challenge when using services which require scoped lifetime. Usually the scope is defined as HTTP request.

Lets define a dependency


    public class Service
    {
        public async Task<string> CallService()
        {
            await Task.Delay(100);
            return "Test";
        }
    }

  • Use ResolverContext: context has an property called `RequestServices.

    [Fact]
    public async Task Part5_ServiceProvider_RequestServices()
    {
        // Create builder and load sdl
        var builder = new SchemaBuilder()
            .Add(@"
                type Query {
                    name: String
                }
                ");

        // Build schema with the resolver
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversMap
            {
                {
                    "Query", "name", async (ResolverContext context) =>
                    {
                        context.ResolvedValue = await context.RequestServices.GetRequiredService<Service>().CallService();
                    }
                }
            }
        });

        // we create an executor with ServiceProvider
        var result = await new Executor(new ExecutorOptions()
        {
            Schema = schema,
            ServiceProvider = new ServiceCollection()
                .AddDefaultTankaGraphQLServices()
                .AddSingleton<Service>()
                .BuildServiceProvider()
        }).Execute(new GraphQLRequest("{name}"));

        result.ShouldMatchJson("""
            {
              "data": {
                "name": "Test"
              }
            }
            """);
    }

  • Use a parameter on delegate, if the property with the name does not exists on ResolverContext it will be resolved from RequestServices

    [Fact]
    public async Task Part5_ServiceProvider_Delegate_with_parameters()
    {
        // Create builder and load sdl
        var builder = new SchemaBuilder()
            .Add(@"
                type Query {
                    name: String
                }
                ");

        // Build schema with the resolver
        var schema = await builder.Build(new SchemaBuildOptions
        {
            Resolvers = new ResolversMap
            {
                {
                    "Query", "name", async (Service service) => await service.CallService()
                }
            }
        });

        // we create an executor with ServiceProvider
        var result = await new Executor(new ExecutorOptions()
        {
            Schema = schema,
            ServiceProvider = new ServiceCollection()
                .AddDefaultTankaGraphQLServices()
                .AddSingleton<Service>()
                .BuildServiceProvider()
        }).Execute(new GraphQLRequest("{name}"));

        result.ShouldMatchJson("""
            {
              "data": {
                "name": "Test"
              }
            }
            """);
    }