asp.net-core-mvcgraphqlasp.net-core-webapi

Unable to resolve service for type 'GraphQL.Http.IDocumentWriter'


I used following only controller in my project out of entire following project.

https://github.com/graphql-dotnet/examples/blob/master/src/AspNetWebApi/Example/Controllers/GraphQLController.cs

Here Controller file is as below.

using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using GraphQL.Http;
using GraphQL.Instrumentation;
using GraphQL.Types;
using GraphQL.Validation.Complexity;

namespace GraphQL.GraphiQL.Controllers
{
    public class GraphQLController : ApiController
    {
        private readonly ISchema _schema;
        private readonly IDocumentExecuter _executer;
        private readonly IDocumentWriter _writer;
        private readonly IDictionary<string, string> _namedQueries;

        public GraphQLController(
            IDocumentExecuter executer,
            IDocumentWriter writer,
            ISchema schema)
        {
            _executer = executer;
            _writer = writer;
            _schema = schema;

            _namedQueries = new Dictionary<string, string>
            {
                ["a-query"] = @"query foo { hero { name } }"
            };
        }

        // This will display an example error
        [HttpGet]
        public Task<HttpResponseMessage> GetAsync(HttpRequestMessage request)
        {
            return PostAsync(request, new GraphQLQuery { Query = "query foo { hero }", Variables = null });
        }

        [HttpPost]
        public async Task<HttpResponseMessage> PostAsync(HttpRequestMessage request, GraphQLQuery query)
        {
            var inputs = query.Variables.ToInputs();
            var queryToExecute = query.Query;

            if (!string.IsNullOrWhiteSpace(query.NamedQuery))
            {
                queryToExecute = _namedQueries[query.NamedQuery];
            }

            var result = await _executer.ExecuteAsync(_ =>
            {
                _.Schema = _schema;
                _.Query = queryToExecute;
                _.OperationName = query.OperationName;
                _.Inputs = inputs;

                _.ComplexityConfiguration = new ComplexityConfiguration { MaxDepth = 15 };
                _.FieldMiddleware.Use<InstrumentFieldsMiddleware>();

            }).ConfigureAwait(false);

            var httpResult = result.Errors?.Count > 0
                ? HttpStatusCode.BadRequest
                : HttpStatusCode.OK;

            var json = _writer.Write(result);

            var response = request.CreateResponse(httpResult);
            response.Content = new StringContent(json, Encoding.UTF8, "application/json");

            return response;
        }
    }

    public class GraphQLQuery
    {
        public string OperationName { get; set; }
        public string NamedQuery { get; set; }
        public string Query { get; set; }
        public Newtonsoft.Json.Linq.JObject Variables { get; set; }
    }
}

When I try to call this controller, it gives me following error.

InvalidOperationException: Unable to resolve service for type 'GraphQL.Http.IDocumentWriter' while attempting to activate 'MyWebAppNamespace.Controllers.GraphQLController'.

Do I need any startup configuration or I can use this standalone controller? What am I missing?


Solution

  • Do I need any startup configuration or I can use this standalone controller? What am I missing?

    As the error describes, it happens because the DI container cannot resolve service for IDocumentWriter.

    It seems that you're missing some service registration. Did you forget to add the IDocumentWrite service ?

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));
    
        services.AddSingleton<IDocumentExecuter, DocumentExecuter>();
        services.AddSingleton<IDocumentWriter, DocumentWriter>();
    
        // ...
        services.AddSingleton<ISchema, StarWarsSchema>();
        // ...
     }
    

    For more details, see startup here

    or I can use this standalone controller?

    No. You're not supposed to do that. That's because your controller depends on the IDocumentExecuter, IDocumentWriter, and ISchema service. They're all resolved by Dependency Injection. You have to register all the services before resolve the controller.