.net core GraphQL, GraphQL.SystemTextJson:不支持"System.Type"实例的序列化和反序列化



在ASP.NET核心5应用程序中,我将GraphQL与GraphQL.SystemTextJson一起使用。当我试图返回一个结果时,我会得到一个System.NotSupportedException,上面写着"System.Type"实例的序列化和反序列化不受支持,应避免,因为它们可能会导致安全问题&";。

我怀疑DocumentWriter的配置中缺少某些内容。

它在ConfigureServices:中是这样配置的

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
...
services.AddScoped<IDocumentWriter, DocumentWriter>();

有什么建议吗?

更新:

为了完整性,正如@AndrewSilver所要求的,我报告了整个代码(改编自https://www.red-gate.com/simple-talk/dotnet/net-development/building-and-consuming-graphql-api-in-asp-net-core-3-1/并移植到.net core 5.0(

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "GraphQlExperiments", Version = "v1" });
});
services.AddScoped<IDocumentExecuter, DocumentExecuter>();
services.AddScoped<IDocumentWriter, DocumentWriter>();
services.AddScoped<AuthorService>();
services.AddScoped<AuthorRepository>();
services.AddScoped<AuthorQuery>();
services.AddScoped<AuthorType>();
services.AddScoped<BlogPostType>();
services.AddScoped<ISchema, GraphQLDemoSchema>();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "GraphQlExperiments v1"));
}

// See: https://github.com/JosephWoodward/graphiql-dotnet
app.UseGraphiQl("/graphiql", "/api/v1/graphql");

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public class Author
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BlogPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Author Author { get; set; }
}
public class AuthorType : ObjectGraphType<Author>
{
public AuthorType()
{
Name = "Author";
Field(_ => _.Id).Description("Author's Id.");
Field(_ => _.FirstName).Description("First name of the author");
Field(_ => _.LastName).Description("Last name of the author");
}
}
public class BlogPostType : ObjectGraphType<BlogPost>
{
public BlogPostType()
{
Name = "BlogPost";
Field(_ => _.Id, type:
typeof(IdGraphType)).Description("The Id of the Blog post.");
Field(_ => _.Title).Description("The title of the blog post.");
Field(_ => _.Content).Description("The content of the blog post.");
}
}
public class AuthorQuery : ObjectGraphType
{
public AuthorQuery(AuthorService authorService)
{
int id = 0;
Field<ListGraphType<AuthorType>>(
name: "authors",
resolve: context =>
{
return authorService.GetAllAuthors();
});
Field<AuthorType>(
name: "author",
arguments: new QueryArguments(new QueryArgument<IntGraphType> { Name = "id" }),
resolve: context =>
{
id = context.GetArgument<int>("id");
return authorService.GetAuthorById(id);
}
);
Field<ListGraphType<BlogPostType>>(
name: "blogs",
arguments: new QueryArguments(new QueryArgument<IntGraphType> { Name = "id" }),
resolve: context =>
{
return authorService.GetPostsByAuthor(id);
}
);
}
}
public class GraphQLQueryDTO
{
public string OperationName { get; set; }
public string NamedQuery { get; set; }
public string Query { get; set; }
public string Variables { get; set; }
}
public class GraphQLDemoSchema : Schema, ISchema
{
public GraphQLDemoSchema(IServiceProvider resolver) : base(resolver)
{
Query = resolver.GetService<AuthorQuery>();
}
}
public class AuthorService
{
private readonly AuthorRepository _authorRepository;
public AuthorService(AuthorRepository
authorRepository)
{
_authorRepository = authorRepository;
}
public List<Author> GetAllAuthors()
{
return _authorRepository.GetAllAuthors();
}
public Author GetAuthorById(int id)
{
return _authorRepository.GetAuthorById(id);
}
public List<BlogPost> GetPostsByAuthor(int id)
{
return _authorRepository.GetPostsByAuthor(id);
}
}
public class AuthorRepository
{
private readonly List<Author> authors = new List<Author>();
private readonly List<BlogPost> posts = new List<BlogPost>();
public AuthorRepository()
{
Author author1 = new Author
{
Id = 1,
FirstName = "Joydip",
LastName = "Kanjilal"
};
Author author2 = new Author
{
Id = 2,
FirstName = "Steve",
LastName = "Smith"
};
BlogPost csharp = new BlogPost
{
Id = 1,
Title = "Mastering C#",
Content = "This is a series of articles on C#.",
Author = author1
};
BlogPost java = new BlogPost
{
Id = 2,
Title = "Mastering Java",
Content = "This is a series of articles on Java",
Author = author1
};
posts.Add(csharp);
posts.Add(java);
authors.Add(author1);
authors.Add(author2);
}
public List<Author> GetAllAuthors()
{
return this.authors;
}
public Author GetAuthorById(int id)
{
return authors.Where(author => author.Id == id).FirstOrDefault<Author>();
}
public List<BlogPost> GetPostsByAuthor(int id)
{
return posts.Where(post => post.Author.Id == id).ToList<BlogPost>();
}
}
[Route("/api/v1/graphql")]
public class GraphQLController : Controller
{
private readonly ISchema _schema;
private readonly IDocumentExecuter _executer;
public GraphQLController(
ISchema schema,
IDocumentExecuter executer
)
{
_schema = schema;
_executer = executer;
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] GraphQLQueryDTO query)
{
var result = await _executer.ExecuteAsync(_ =>
{
_.Schema = _schema;
_.Query = query.Query;
_.Inputs = query.Variables?.ToInputs();
});
if (result.Errors?.Count > 0)
{
return BadRequest();
}
return Ok(result.Data);
}
}

这是一个触发错误的示例请求:

query {
author (id: 1){
id
firstName
lastName
}
blogs
{
id
title
content
}
}

我解决了创建自定义JsonConverter:的问题

public class CustomJsonConverterForType : JsonConverter<Type>
{
public override Type Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
// Caution: Deserialization of type instances like this 
// is not recommended and should be avoided
// since it can lead to potential security issues.
// If you really want this supported (for instance if the JSON input is trusted):
// string assemblyQualifiedName = reader.GetString();
// return Type.GetType(assemblyQualifiedName);
throw new NotSupportedException();
}
public override void Write(
Utf8JsonWriter writer,
Type value,
JsonSerializerOptions options
)
{
string assemblyQualifiedName = value.AssemblyQualifiedName;
// Use this with caution, since you are disclosing type information.
writer.WriteStringValue(assemblyQualifiedName);
}
}

然后,在配置服务中:

services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.Converters.Add(new CustomJsonConverterForType());
});

我使用文档中显示的代码片段解决了这个问题:https://graphql-dotnet.github.io/docs/migrations/migration3

[HttpPost]
public async Task<IActionResult> Post([FromBody] GraphQLQueryDTO query)
{
var result = await _executer.ExecuteAsync(_ =>
{
_.Schema = _schema;
_.Query = query.Query;
_.Inputs = query.Variables?.ToInputs();
});
/* ----------- Added this ---------------------------------*/
HttpContext.Response.ContentType = "application/json";
HttpContext.Response.StatusCode = 200; // OK
var writer = new GraphQL.SystemTextJson.DocumentWriter();
await writer.WriteAsync(HttpContext.Response.Body, result);*
/* ------------------------------------------------------*/
if (result.Errors?.Count > 0)
{
return BadRequest();
}
return Ok(result.Data);
}
}

不使用System.Text.Json.JsonSearalizer而使用NewtonSoft.JsonConvert.SearalizeObject

在您的startup.cs中,在ConfigureServices 中

在AddControllers((之后添加AddNewtonsoftJson((

services.AddControllers((.AddNewtonsoftJson((;

最新更新