C# GraphQL模型与System.Text.Json.JsonException斗争

C# GraphQL模型与System.Text.Json.JsonException斗争,c#,graphql,graphql-dotnet,C#,Graphql,Graphql Dotnet,我创建了一个新的.NET核心项目,并安装了GraphQL、GraphiQL和GraphQL.SystemTextJson包 当运行应用程序时,这就是我得到的 此外,异常消息GraphiQL无法找到架构文档 首先,我有两个实体,用户和任务 public sealed class User { public Guid Id { get; set; } } public sealed class Task { public Guid Id { get; set; } } 它们都有

我创建了一个新的.NET核心项目,并安装了GraphQL、GraphiQL和GraphQL.SystemTextJson包

当运行应用程序时,这就是我得到的

此外,异常消息GraphiQL无法找到架构文档

首先,我有两个实体,用户和任务

public sealed class User
{
    public Guid Id { get; set; }
}

public sealed class Task
{
    public Guid Id { get; set; }
}
它们都有各自的表示图类型

public sealed class UserType : ObjectGraphType<User>
{
    public UserType()
    {
        Name = nameof(User);
        Field(user => user.Id).Description("The user id.");
    }
}

public sealed class TaskType : ObjectGraphType<Task>
{
    public TaskType()
    {
        Name = nameof(Task);
        Field(task => task.Id).Description("The task id.");
    }
}
ConfigureServices
的启动文件中,我在调用
services.AddControllers()

最后,我实现了API控制器

[ApiController]
[Route("[controller]")]
public sealed class GraphQLController : Controller
{
    private readonly ISchema _schema;
    private readonly IDocumentExecuter _documentExecuter;

    public GraphQLController(ISchema schema, IDocumentExecuter documentExecuter)
    {
        _schema = schema;
        _documentExecuter = documentExecuter;
    }

    public async Task<IActionResult> Post([FromBody] GraphQLRequest graphQlRequest)
    {
        ExecutionOptions executionOptions = new ExecutionOptions()
        {
            Schema = _schema,
            Query = graphQlRequest.Query,
            Inputs = graphQlRequest.Variables?.ToInputs()
        };

        ExecutionResult executionResult = await _documentExecuter.ExecuteAsync(executionOptions);

        if (executionResult.Errors != null)
            return BadRequest(executionResult);

        return Ok(executionResult);
    }
}

我现在迁移到了.NET5,却收到了这个错误


我添加了一个复制库


这是Json解析器的经典之作。如果您有导航属性或相互引用的属性

通常,可以通过返回映射结果或调整Json序列化程序设置来修复此问题

我不确定这是否在.Net Core 3.1中修复 但是您可以添加到startup.cs

如果尚未安装,请安装
newtonsoftjson

services
  .AddControllers()
  .AddNewtonsoftJson(options =>
  {
      options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
  });
希望这能解决问题

这里有一些关于这个问题的文章


您在.Net 5中的错误与未注册的图形类型有关。如果在调试设置中启用所有异常并禁用“仅我的代码”,您将看到此错误

System.InvalidOperationException: 'Required service for type API.GraphTypes.UserType not found'
This exception was originally thrown at this call stack:
    GraphQL.Utilities.ServiceProviderExtensions.GetRequiredService(System.IServiceProvider, System.Type) in ServiceProviderExtensions.cs
    GraphQL.Types.Schema.CreateTypesLookup.AnonymousMethod__68_1(System.Type) in Schema.cs
    GraphQL.Types.GraphTypesLookup.Create.AnonymousMethod__0(System.Type) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.AddTypeIfNotRegistered(System.Type, GraphQL.Types.TypeCollectionContext) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.HandleField(GraphQL.Types.IComplexGraphType, GraphQL.Types.FieldType, GraphQL.Types.TypeCollectionContext, bool) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.AddType(GraphQL.Types.IGraphType, GraphQL.Types.TypeCollectionContext) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.Create(System.Collections.Generic.IEnumerable<GraphQL.Types.IGraphType>, System.Collections.Generic.IEnumerable<GraphQL.Types.DirectiveGraphType>, System.Func<System.Type, GraphQL.Types.IGraphType>, GraphQL.Conversion.INameConverter, bool) in GraphTypesLookup.cs
    GraphQL.Types.Schema.CreateTypesLookup() in Schema.cs
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
更新后的
GraphQLController.cs

[ApiController]
[Route("[controller]")]
public sealed class GraphQLController : Controller
{
    private readonly ISchema _schema;
    private readonly IDocumentExecuter _documentExecuter;
    private readonly IDocumentWriter _documentWriter;

    public GraphQLController(ISchema schema, IDocumentExecuter documentExecuter, IDocumentWriter documentWriter)
    {
        _schema = schema;
        _documentExecuter = documentExecuter;
        _documentWriter = documentWriter;
    }

    public async Task Post([FromBody] GraphQLRequest graphQlRequest)
    {
        ExecutionOptions executionOptions = new ExecutionOptions()
        {
            Schema = _schema,
            Query = graphQlRequest.Query,
            Inputs = graphQlRequest.Variables?.ToInputs()
        };

        ExecutionResult executionResult = await _documentExecuter.ExecuteAsync(executionOptions);

        await WriteResponseAsync(HttpContext, executionResult);
    }

    private async Task WriteResponseAsync(HttpContext context, ExecutionResult result)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = result.Errors?.Any() == true ? (int)HttpStatusCode.BadRequest : (int)HttpStatusCode.OK;
    
        await _documentWriter.WriteAsync(context.Response.Body, result);
    }
}

graphQlRequest
的值是多少?您可以将其值的json表示添加到您的问题中。OfirD我将值添加到我的问题中:)您可以将完整的Silion上载到Github吗?如果人们可以克隆并玩你的reposure,那么帮助会更容易。给我一个second@Artur你可以在这里找到嘿,谢谢你的回答。不幸的是,我没有使用Newtonsoft。由于Microsoft提供了自己的JSON库,现在我安装了
GraphQL.SystemTextJson
包,正如这里的文档所述,在system.text.JSON由于referenceloop处理错误而不够成熟之前,这是一个已知的问题。强烈建议您要么更新到.net core 5,要么将system.text.json替换为newtonsofts.:)顺便说一句:这里有一个微软自己的文档链接,他们的json序列化程序:即使在3.1版本中,它似乎仍然不支持我迁移到.NET 5的referenceloop errorhmm,但不幸的是仍然出现了一个错误。。(更新了我的问题)我理解您使用Newtonsoft的原因,但我希望避免使用外部软件包作为解决方法……:SSo它不再是referenceloop处理错误。万岁!不幸的是,现在您在system.text.json中遇到了另一个不受支持的功能。例如,看看这个已注册的问题,它说明了与system.text.json引发此异常相同的事实。不过,我最强烈的建议还是改用newtonsoft,它已经存在了很长时间,并且可以完成这项工作。嗯:/谢谢。但我认为我的代码是错误的,因为其他人也使用这个软件包,或者至少有人在发布它之前尝试过它?我建议使用中间件作为使用库的更简单、更干净的方式。看这个例子:是的,错误消失了!但是GraphiQL无法加载架构。。我如何添加它?嗯,在注册缺少的类型并用
IDocumentWriter
将响应写入后,我实际上可以在文档中看到模式。我将用控制器代码更新答案
[ApiController]
[Route("[controller]")]
public sealed class GraphQLController : Controller
{
    private readonly ISchema _schema;
    private readonly IDocumentExecuter _documentExecuter;

    public GraphQLController(ISchema schema, IDocumentExecuter documentExecuter)
    {
        _schema = schema;
        _documentExecuter = documentExecuter;
    }

    public async Task<IActionResult> Post([FromBody] GraphQLRequest graphQlRequest)
    {
        ExecutionOptions executionOptions = new ExecutionOptions()
        {
            Schema = _schema,
            Query = graphQlRequest.Query,
            Inputs = graphQlRequest.Variables?.ToInputs()
        };

        ExecutionResult executionResult = await _documentExecuter.ExecuteAsync(executionOptions);

        if (executionResult.Errors != null)
            return BadRequest(executionResult);

        return Ok(executionResult);
    }
}
query IntrospectionQuery {
  __schema {
    queryType { name }
    mutationType { name }
    subscriptionType { name }
    types {
      ...FullType
    }
    directives {
      name
      description
      locations
      args {
        ...InputValue
      }
    }
  }
}

fragment FullType on __Type {
  kind
  name
  description
  fields(includeDeprecated: true) {
    name
    description
    args {
      ...InputValue
    }
    type {
      ...TypeRef
    }
    isDeprecated
    deprecationReason
  }
  inputFields {
    ...InputValue
  }
  interfaces {
    ...TypeRef
  }
  enumValues(includeDeprecated: true) {
    name
    description
    isDeprecated
    deprecationReason
  }
  possibleTypes {
    ...TypeRef
  }
}

fragment InputValue on __InputValue {
  name
  description
  type { ...TypeRef }
  defaultValue
}

fragment TypeRef on __Type {
  kind
  name
  ofType {
    kind
    name
    ofType {
      kind
      name
      ofType {
        kind
        name
        ofType {
          kind
          name
          ofType {
            kind
            name
            ofType {
              kind
              name
              ofType {
                kind
                name
              }
            }
          }
        }
      }
    }
  }
}
services
  .AddControllers()
  .AddNewtonsoftJson(options =>
  {
      options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
  });
System.InvalidOperationException: 'Required service for type API.GraphTypes.UserType not found'
This exception was originally thrown at this call stack:
    GraphQL.Utilities.ServiceProviderExtensions.GetRequiredService(System.IServiceProvider, System.Type) in ServiceProviderExtensions.cs
    GraphQL.Types.Schema.CreateTypesLookup.AnonymousMethod__68_1(System.Type) in Schema.cs
    GraphQL.Types.GraphTypesLookup.Create.AnonymousMethod__0(System.Type) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.AddTypeIfNotRegistered(System.Type, GraphQL.Types.TypeCollectionContext) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.HandleField(GraphQL.Types.IComplexGraphType, GraphQL.Types.FieldType, GraphQL.Types.TypeCollectionContext, bool) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.AddType(GraphQL.Types.IGraphType, GraphQL.Types.TypeCollectionContext) in GraphTypesLookup.cs
    GraphQL.Types.GraphTypesLookup.Create(System.Collections.Generic.IEnumerable<GraphQL.Types.IGraphType>, System.Collections.Generic.IEnumerable<GraphQL.Types.DirectiveGraphType>, System.Func<System.Type, GraphQL.Types.IGraphType>, GraphQL.Conversion.INameConverter, bool) in GraphTypesLookup.cs
    GraphQL.Types.Schema.CreateTypesLookup() in Schema.cs
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
private async Task WriteResponseAsync(HttpContext context, ExecutionResult result)
{
    context.Response.ContentType = "application/json";
    context.Response.StatusCode = result.Errors?.Any() == true ? (int)HttpStatusCode.BadRequest : (int)HttpStatusCode.OK;

    await _documentWriter.WriteAsync(context.Response.Body, result);
}
[ApiController]
[Route("[controller]")]
public sealed class GraphQLController : Controller
{
    private readonly ISchema _schema;
    private readonly IDocumentExecuter _documentExecuter;
    private readonly IDocumentWriter _documentWriter;

    public GraphQLController(ISchema schema, IDocumentExecuter documentExecuter, IDocumentWriter documentWriter)
    {
        _schema = schema;
        _documentExecuter = documentExecuter;
        _documentWriter = documentWriter;
    }

    public async Task Post([FromBody] GraphQLRequest graphQlRequest)
    {
        ExecutionOptions executionOptions = new ExecutionOptions()
        {
            Schema = _schema,
            Query = graphQlRequest.Query,
            Inputs = graphQlRequest.Variables?.ToInputs()
        };

        ExecutionResult executionResult = await _documentExecuter.ExecuteAsync(executionOptions);

        await WriteResponseAsync(HttpContext, executionResult);
    }

    private async Task WriteResponseAsync(HttpContext context, ExecutionResult result)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = result.Errors?.Any() == true ? (int)HttpStatusCode.BadRequest : (int)HttpStatusCode.OK;
    
        await _documentWriter.WriteAsync(context.Response.Body, result);
    }
}