ASP.NET POST控制器中嵌套JSON列表反序列化为Object问题
解决ASP.NET中嵌套KeyValue结构反序列化问题
问题分析
你当前的控制器接收List(Of KeyValueClass(Of String, Object))类型参数,原始类型值(如数字)能正常反序列化,但LinkedIDs对应的Value被解析为Object,无法自动转换为List(Of KeyValuePair(Of String, Integer))。核心原因是Object类型无明确类型信息,JSON序列化器无法推断嵌套数组的具体类型。
解决方案
方案1:改用强类型模型(推荐)
直接定义匹配JSON结构的强类型模型,避免使用Object,让序列化器自动处理类型映射:
' 定义嵌套的KeyValue类 Public Class KeyValuePairModel(Of TKey, TValue) Public Property Key As TKey Public Property Value As TValue End Class ' 定义完整的输入模型 Public Class InputCommandModel Public Property CardCode As Integer Public Property PersonID As Integer Public Property LinkedIDs As List(Of KeyValuePairModel(Of String, Integer)) End Class
修改控制器方法:
<HttpPost> Function InputCommand(model As InputCommandModel) As IActionResult ' 这里LinkedIDs已正确反序列化为List(Of KeyValuePairModel(Of String, Integer)) ' 如需转换为KeyValuePair集合,可使用: Dim linkedIDPairs = model.LinkedIDs.Select(Function(kv) New KeyValuePair(Of String, Integer)(kv.Key, kv.Value)).ToList() ' 业务逻辑处理 Return Ok() End Function
方案2:自定义JSON转换器(保留原模型结构)
如果必须保留List(Of KeyValueClass(Of String, Object))的结构,可通过自定义JSON转换器识别嵌套的KeyValue数组并转换为目标类型。
以Newtonsoft.Json为例:
- 定义转换器:
Imports Newtonsoft.Json Imports System.Collections.Generic Imports System.Linq Public Class NestedKeyValueListConverter Inherits JsonConverter(Of Object) Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object ' 判断当前JSON节点是否为数组 If reader.TokenType = JsonToken.StartArray Then ' 反序列化为嵌套的KeyValueClass集合,再转换为KeyValuePair列表 Dim nestedList = serializer.Deserialize(Of List(Of KeyValueClass(Of String, Integer)))(reader) Return nestedList.Select(Function(kv) New KeyValuePair(Of String, Integer)(kv.Key, kv.Value)).ToList() End If ' 非数组类型按默认逻辑反序列化 Return serializer.Deserialize(reader) End Function Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer) serializer.Serialize(writer, value) End Function Public Overrides Function CanConvert(objectType As Type) As Boolean Return objectType = GetType(Object) End Function End Class
- 在
KeyValueClass的Value属性上标记转换器:
Public Class KeyValueClass(Of TKey, TValue) Public Property Key As TKey <JsonConverter(GetType(NestedKeyValueListConverter))> Public Property Value As TValue End Class
以System.Text.Json为例:
- 定义转换器:
Imports System.Text.Json Imports System.Text.Json.Serialization Imports System.Collections.Generic Imports System.Linq Public Class NestedKeyValueListConverter Inherits JsonConverter(Of Object) Public Overrides Function Read(reader As Utf8JsonReader, typeToConvert As Type, options As JsonSerializerOptions) As Object If reader.TokenType = JsonTokenType.StartArray Then Dim nestedList = JsonSerializer.Deserialize(Of List(Of KeyValueClass(Of String, Integer)))(reader, options) Return nestedList.Select(Function(kv) New KeyValuePair(Of String, Integer)(kv.Key, kv.Value)).ToList() End If Return JsonSerializer.Deserialize(reader, typeToConvert, options) End Function Public Overrides Sub Write(writer As Utf8JsonWriter, value As Object, options As JsonSerializerOptions) JsonSerializer.Serialize(writer, value, options) End Function End Class
- 在Startup中全局注册转换器:
services.AddControllers() .AddJsonOptions(Sub(options) options.JsonSerializerOptions.Converters.Add(New NestedKeyValueListConverter()) End Sub)
方案3:手动类型转换(应急方案)
如果不想修改模型或添加转换器,可在控制器中手动将Object转换为目标类型:
<HttpPost> Function InputCommand(Input As List(Of KeyValueClass(Of String, Object))) As IActionResult Dim linkedIDsItem = Input.FirstOrDefault(Function(kv) kv.Key = "LinkedIDs") If linkedIDsItem IsNot Nothing Then ' 手动反序列化Object为List(Of KeyValuePair(Of String, Integer)) Dim linkedIDsJson = JsonConvert.SerializeObject(linkedIDsItem.Value) Dim linkedIDs = JsonConvert.DeserializeObject(Of List(Of KeyValuePair(Of String, Integer)))(linkedIDsJson) ' 使用linkedIDs处理业务逻辑 End If Return Ok() End Function
内容的提问来源于stack exchange,提问作者Machshevet
相关产品推荐
相关产品推荐

