.NET Core GraphQL返回Dictionary反序列化异常的更优处理方案咨询
解决Blazor WebAssembly中GraphQL返回数组无法反序列化为Dictionary的问题
针对你遇到的GraphQL返回JSON数组无法反序列化为Dictionary<string, decimal>的问题,除了Newtonsoft序列化转换器,还有以下更贴合Blazor生态或更彻底的解决方案:
1. 调整GraphQL后端的字段输出格式(最优解)
问题根源在于后端将Dictionary序列化为了JSON数组(如[{"Key":"x","Value":1.0},...]),而客户端期望的是JSON对象格式(如{"x":1.0,...})。如果能控制后端代码,直接修改GraphQL的字段序列化逻辑是最彻底的解决方式:
- 若使用HotChocolate等GraphQL框架,可为
SomeClass的Items字段配置自定义解析器或类型映射,强制输出JSON对象而非数组。 - 示例(HotChocolate):
这样后端直接输出客户端期望的JSON对象格式,无需修改任何客户端代码。public class SomeClassType : ObjectType<SomeClass> { protected override void Configure(IObjectTypeDescriptor<SomeClass> descriptor) { descriptor.Field(f => f.Items) .Type<ObjectType<Dictionary<string, decimal>>>() .Resolve(ctx => ctx.Parent<SomeClass>().Items); } }
2. 使用System.Text.Json自定义转换器(贴合Blazor默认生态)
Blazor WebAssembly默认使用System.Text.Json,编写专属转换器比引入Newtonsoft更轻量且性能更优:
- 首先实现转换器:
public class DictionaryFromArrayConverter : JsonConverter<Dictionary<string, decimal>> { public override Dictionary<string, decimal> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException("JSON格式错误:预期为数组类型"); var dictionary = new Dictionary<string, decimal>(); while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) { // 解析数组中的键值对对象 reader.Read(); // 进入对象 reader.Read(); // 读取"Key"属性名 reader.Read(); // 获取Key值 var key = reader.GetString(); reader.Read(); // 读取"Value"属性名 reader.Read(); // 获取Value值 var value = reader.GetDecimal(); dictionary[key] = value; reader.Read(); // 退出当前对象 } return dictionary; } public override void Write(Utf8JsonWriter writer, Dictionary<string, decimal> value, JsonSerializerOptions options) { // 若需要序列化字典,可按原逻辑或转为数组,按需实现 JsonSerializer.Serialize(writer, value, options); } } - 然后在Program.cs中全局注册转换器(以GraphQL.Client为例):
注册后所有涉及builder.Services.AddGraphQLClient(options => { options.EndPoint = new Uri("https://your-graphql-api-url"); options.JsonSerializerOptions.Converters.Add(new DictionaryFromArrayConverter()); });Dictionary<string, decimal>的反序列化都会自动适配数组格式。
3. 中间层DTO映射(轻量局部解决方案)
若不想修改全局序列化配置,可创建客户端专用DTO,手动完成格式转换:
- 定义DTO类:
public class SomeClassDto { public int Id { get; set; } public List<KeyValuePair<string, decimal>> Items { get; set; } } - 查询后转换为目标类型:
该方案逻辑直观,仅需在使用处做局部转换,适合数据模型使用范围有限的场景。var queryResult = await graphQLClient.SendQueryAsync<SomeClassDto>(yourGetDataQuery); var targetObject = new SomeClass { Id = queryResult.Data.Id, Items = queryResult.Data.Items.ToDictionary(kv => kv.Key, kv => kv.Value) };
内容的提问来源于stack exchange,提问作者Ali Khan
相关产品推荐
相关产品推荐

