[英]GraphQL models struggling with System.Text.Json.JsonException
I created a new .NET Core project and installed the packages GraphQL, GraphiQL and GraphQL.SystemTextJson.我创建了一个新的 .NET 核心项目并安装了包 GraphQL、GraphiQL 和 GraphQL.SystemTextJson。
When running the application this is what I get运行应用程序时,这就是我得到的
Besides the exception message GraphiQL wasn't able to find a schema documentation.除了异常消息 GraphiQL 无法找到架构文档。
First of all I have two entities, users and tasks.首先,我有两个实体,用户和任务。
public sealed class User
{
public Guid Id { get; set; }
}
public sealed class Task
{
public Guid Id { get; set; }
}
and both of them have their representing graph type并且他们都有自己的代表图类型
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.");
}
}
I created the query holding all the "actions" the client can execute我创建了包含客户端可以执行的所有“操作”的查询
public sealed class GraphQLQuery : ObjectGraphType
{
private readonly List<User> _users = new List<User>();
private readonly List<Task> _tasks = new List<Task>();
public GraphQLQuery()
{
Field<ListGraphType<UserType>>(
"users",
"Returns a collection of users.",
resolve: context => _users);
Field<ListGraphType<TaskType>>(
"tasks",
"Returns a collection of tasks.",
resolve: context => _tasks);
}
}
and register that query for the schema并为模式注册该查询
public sealed class GraphQLSchema : GraphQL.Types.Schema
{
public GraphQLSchema(GraphQLQuery graphQLQuery, IServiceProvider serviceProvider) : base(serviceProvider)
{
Query = graphQLQuery;
}
}
In the startup file in the ConfigureServices
I added this code to register all the required services before calling services.AddControllers()
在
ConfigureServices
的启动文件中,我添加了此代码以在调用services.AddControllers()
之前注册所有必需的服务
serviceCollection
.AddSingleton<IDocumentExecuter, DocumentExecuter>()
.AddSingleton<IDocumentWriter, DocumentWriter>()
.AddSingleton<ISchema, GraphQLSchema>()
.AddSingleton<GraphQLQuery>()
and in the Configure
method I call app.UseGraphiQl()
at first.在
Configure
方法中,我首先调用app.UseGraphiQl()
。
The corresponding GraphQL request DTO对应的GraphQL请求DTO
public sealed class GraphQLRequest
{
public string OperationName { get; set; }
public string Query { get; set; }
[JsonConverter(typeof(ObjectDictionaryConverter))]
public Dictionary<string, object> Variables { get; set; }
}
Lastly I implemented the API controller最后我实现了 API controller
[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);
}
}
Does someone know what's wrong here?有人知道这里有什么问题吗? I can't see problems like circular dependency etc.
我看不到循环依赖等问题。
When running the application the graphQlRequest
contains the following values运行应用程序时,
graphQlRequest
包含以下值
. .
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
}
}
}
}
}
}
}
}
I migrated to .NET 5 now and get this error instead我现在迁移到 .NET 5 并收到此错误
I added a reproduction repository我添加了一个复制存储库
https://github.com/olaf-svenson/graphql-net-reproduction https://github.com/olaf-svenson/graphql-net-reproduction
It's a classic for Json resolvers.这是 Json 解析器的经典之作。 if you have navigation properties or properties that reference eachother.
如果您有导航属性或相互引用的属性。
Often this can be fixed by either returning a mapped result, or by adjusting the Json Serializer settings.通常可以通过返回映射结果或调整 Json 串行器设置来解决此问题。
I'm unsure whether this is fixed in.Net Core 3.1 but you can to the startup.cs add我不确定这是否已在.Net Core 3.1 中修复,但您可以在 startup.cs 添加
install Newtonsoft Json
if you haven't already.如果您还没有安装
Newtonsoft Json
。
services
.AddControllers()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
hope this resolves it.希望这能解决它。
here's some article about the issue.这里有一些关于这个问题的文章。
https://dotnetcoretutorials.com/2020/03/15/fixing-json-self-referencing-loop-exceptions/ https://dotnetcoretutorials.com/2020/03/15/fixing-json-self-referencing-loop-exceptions/
.net core 3 not having ReferenceLoopHandling in AddJsonOptions .net 核心 3 在 AddJsonOptions 中没有 ReferenceLoopHandling
Your error in.Net 5 related to unregistered graph types.您在.Net 5 中的错误与未注册的图形类型有关。 If you enable all exceptions and disable "Just My Code" in debug settings you will see this error
如果您在调试设置中启用所有异常并禁用“仅我的代码”,您将看到此错误
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()
Adding UserType
and TaskType
to DI container solves this error.将
UserType
和TaskType
添加到 DI 容器可以解决此错误。
Now, your original problem: you should use IDocumentWriter
to write the response, you can't just serialize executionResult
by returning Ok(executionResult)
.现在,您的原始问题:您应该使用
IDocumentWriter
来编写响应,您不能只通过返回Ok(executionResult)
来序列化executionResult
。 Use this code to write response (stolen from official graphql-dotnet/examples repo):使用此代码编写响应(从官方graphql-dotnet/examples repo 窃取):
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);
}
The updated GraphQLController.cs
更新后的
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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.