c# - 无法序列化字典在 C# 中
问题描述
我将请求模型作为参数传递给我的 POST 请求的 API,请求模型上的属性之一是 Dictionary<int, OrderFood> 类型。我正在使用 Swagger 测试操作方法,我得到的错误响应是:
“不支持集合类型'System.Collections.Generic.Dictionary`2[System.int32, OrderFood]。'”
我知道目前不支持序列化非字符串键字典,我需要实现自定义 JSON 转换器。这是请求模型类:
[JsonConverter(typeof(JsonNonStringKeyDictionaryConverter<int, OrderFood>))]
public class FoodOrderRequestModel
{
public string ModelName { get; set; }
public string DisplayName { get; set; }
public string Type { get; set; }
public object ModelValue { get; set; }
public object DisplayValue { get; set; }
public Dictionary<int, OrderFood> Items { get; set; }
}
这是转换器:
internal sealed class JsonNonStringKeyDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
{
public override IDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var convertedType = typeof(Dictionary<,>)
.MakeGenericType(typeof(string), typeToConvert.GenericTypeArguments[1]);
var value = JsonSerializer.Deserialize(ref reader, convertedType, options);
var instance = (Dictionary<TKey, TValue>)Activator.CreateInstance(
typeToConvert,
BindingFlags.Instance | BindingFlags.Public,
null,
null,
CultureInfo.CurrentCulture);
var enumerator = (IEnumerator)convertedType.GetMethod("GetEnumerator")!.Invoke(value, null);
var parse = typeof(TKey).GetMethod("Parse", 0, BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Any, new[] { typeof(string) }, null);
if (parse == null)
{
throw new NotSupportedException($"{typeof(TKey)} as TKey in IDictionary<TKey, TValue> is not supported.");
}
while (enumerator.MoveNext())
{
var element = (KeyValuePair<string?, TValue>)enumerator.Current;
instance.Add((TKey)parse.Invoke(null, new[] { element.Key }), element.Value);
}
return instance;
}
public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializerOptions options)
{
var convertedDictionary = new Dictionary<string?, TValue>(value.Count);
foreach (var (k, v) in value)
{
convertedDictionary[k?.ToString()] = v;
}
JsonSerializer.Serialize(writer, convertedDictionary, options);
convertedDictionary.Clear();
}
}
internal sealed class JsonNonStringKeyDictionaryConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
if (typeToConvert.GenericTypeArguments[0] == typeof(string))
{
return false;
}
return typeToConvert.GetInterface("IDictionary") != null;
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var converterType = typeof(JsonNonStringKeyDictionaryConverter<,>)
.MakeGenericType(typeToConvert.GenericTypeArguments[0], typeToConvert.GenericTypeArguments[1]);
var converter = (JsonConverter)Activator.CreateInstance(
converterType,
BindingFlags.Instance | BindingFlags.Public,
null,
null,
CultureInfo.CurrentCulture);
return converter;
}
}
序列化发生在我的 API 上的任何断点之前,所以我不确定如何测试我的转换器以查看它是否已添加到管道中。我也不确定 JsonNonStringKeyDictionaryConverter<,> 的位置,因为我已经看到它直接位于属性上方的某些实现。非常感谢任何建议或帮助。
解决方案
将 System.Text.Json NuGet 包更新/添加到 LTS 版本 5.0.1 适用于 .NET Core 3.1 应用程序。
特别感谢@CoolBots在github上的主题讨论 https://github.com/dotnet/runtime/issues/30524#issuecomment-524619972
推荐阅读
- c++ - 如果我已经检查了 typeid,为什么不使用 static_cast 而不是 dynamic_cast?
- sql - Snowflake 查询优化器是否尊重 CTE?
- class - “任意”的实例如何查找树?
- c++ - 支持行和列查找的 C++ 容器
- c# - Core Web Api - 错误:动作从请求正文绑定了多个参数
- mysql - mysql:重试事务指定次数
- javascript - 嵌入未正确包含 svg
- html - 悬停时滑出小部件
- plugins - Microsoft Teams 状态与 Genesys Workspace Edition 的集成?
- java - 缺少工件 org.docx4j:docx4j-samples-resources:jar:8.2.8