如何解决GraphQL 模型在 System.Text.Json.JsonException 中挣扎
我创建了一个新的 .NET Core 项目并安装了 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.");
}
}
我创建了包含客户端可以执行的所有“操作”的查询
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);
}
}
public sealed class GraphQLSchema : GraphQL.Types.Schema
{
public GraphQLSchema(GraphQLQuery graphQLQuery,IServiceProvider serviceProvider) : base(serviceProvider)
{
Query = graphQLQuery;
}
}
在 ConfigureServices
的启动文件中,我添加了此代码以在调用 services.AddControllers()
之前注册所有必需的服务
serviceCollection
.AddSingleton<IDocumentExecuter,DocumentExecuter>()
.AddSingleton<IDocumentWriter,DocumentWriter>()
.AddSingleton<ISchema,GraphQLSchema>()
.AddSingleton<GraphQLQuery>()
在 Configure
方法中,我首先调用 app.UseGraphiQl()
。
对应的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; }
}
最后我实现了 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);
}
}
有人知道这里出了什么问题吗?我看不到循环依赖等问题。
运行应用程序时,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
}
}
}
}
}
}
}
}
我现在迁移到 .NET 5 并收到此错误
https://github.com/olaf-svenson/graphql-net-reproduction
解决方法
这是对JSON解析器经典。如果你有导航属性或性质参考海誓山盟。
通常,这可以通过任一返回映射结果,或通过调节JSON序列设置固定的。
我不能确定是否这是固定在.net核心3.1 但你可以到startup.cs添加
安装Newtonsoft Json
如果已经没有。
services
.AddControllers()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
希望这能解决它。
下面是关于这个问题的一些文章。
https://dotnetcoretutorials.com/2020/03/15/fixing-json-self-referencing-loop-exceptions/
.net core 3 not having ReferenceLoopHandling in AddJsonOptions
,您在 .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()
将 UserType
和 TaskType
添加到 DI 容器可以解决此错误。
现在,您的原始问题是:您应该使用 IDocumentWriter
来编写响应,您不能仅通过返回 executionResult
来序列化 Ok(executionResult)
。
使用此代码编写响应(从官方 graphql-dotnet/examples 存储库中窃取):
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);
}
更新后的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);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。