Skip to main content
 首页 » 编程设计

c#中ModelState 错误中Newtonsoft.Json.JsonSerializationException : Cannot populate list type System.Net.TrackingStringDictionary

2025年12月25日24zhengyun_ustc

尝试调用 webApi 时出现标题错误。 这是我的类(class):

public class NotificationDTO 
{ 
    public long idCompanyService { get; set; } 
 
    public DocTypeEnum DocumentType { get; set; } 
 
    public List<Tuple<string, byte[], System.Net.Mime.ContentType>> Attachments { get; set; } 
} 

这在我的对象中:

NotificationDTO notifDto = new NotificationDTO() 
                { 
                    idCompanyService = idCompServ, 
                    DocumentType = DocType, 
                    Attachments = listAttac 
                }; 

这是电话:

HttpContent content = new StringContent(JsonConvert.SerializeObject(notifDto), Encoding.UTF8, "application/json"); 
HttpResponseMessage response = client.PostAsync(uri, content).Result; 

这是一个 Json:

{"idCompanyService":1234,"DocumentType":0,"Attachments":[{"Item1":"test.pdf","Item2":"ThisIsABase64Data","Item3":{"Boundary":null,"CharSet":null,"MediaType":"application/pdf","Name":null,"Parameters":[]}}} 

附件有问题,因为是 List<Tuple<string, byte[], ContentType>> .

错误消息:

Exception: Newtonsoft.Json.JsonSerializationException: Cannot populate list type System.Net.TrackingStringDictionary. Path 'Attachments.$values[0].Item3.Parameters.$values', line 1, position 105257. 
   in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) 
   in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id) 
   in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
   in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) 
   in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) 
   in Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) 

Object Example

尝试示例: 您可以使用简单的 Web API Controller 重现该错误:

[HttpPost] 
[Route("api/TestNotification")] 
public IHttpActionResult TestNotification(NotificationDTO dto) 
{ 
    return Ok(); 
} 

在 Post Caller 中像这样的 Json:

{"idCompanyService":1234,"DocumentType":1,"Attachments":[{"Item1":"wqere.pdf","Item2":"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=","Item3":{"Boundary":null,"CharSet":null,"MediaType":"application/pdf","Name":null,"Parameters":[]}},{"Item1":"ewqeqwe.xml","Item2":"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=","Item3":{"Boundary":null,"CharSet":null,"MediaType":"text/xml","Name":null,"Parameters":[]}}]} 

最后,一个 .Net fiddle 演示了将上述 JSON 字符串反序列化为 NotificationDTO 时失败的情况。直接通过:

var dto = JsonConvert.DeserializeObject<NotificationDTO>(json); 

可以在这里找到:https://dotnetfiddle.net/EaPhm9 .

请您参考如下方法:

这里真正的问题是您的 DTO 引用 System.Net.Mime.ContentType 类型的对象其中又有一个成员 ContentType.Parameters其声明类型为 System.Collections.Specialized.StringDictionary (和实际类型 System.Net.TrackingStringDictionary )。 不幸的是,这种古老的类型(来自.Net 1.1)甚至没有实现IDictionary。由于它仅实现无类型枚举器 System.Collections.IEnumerable,Json.NET 无法知道如何反序列化它,并会在要求这样做时抛出您所看到的异常。

因此有必要写一个 custom JsonConverter反序列化该类型或派生自该类型的对象:

using System.Collections.Specialized; 
 
public class StringDictionaryConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
        return typeof(StringDictionary).IsAssignableFrom(objectType); 
    } 
 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
        var tokenType = reader.SkipComments().TokenType; 
        if (tokenType == JsonToken.Null) 
            return null; 
 
        var dictionary = existingValue as StringDictionary ?? (StringDictionary)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator(); 
 
        switch (tokenType) 
        { 
            case JsonToken.StartArray: 
                { 
                    // StringDictionary serialized without converter 
                    var list = serializer.Deserialize<List<KeyValuePair<string, string>>>(reader); 
                    foreach (var pair in list) 
                        dictionary.Add(pair.Key, pair.Value); 
                } 
                break; 
 
            case JsonToken.StartObject: 
                { 
                    // StringDictionary serialized with converter 
                    var typedDictionary = serializer.Deserialize<Dictionary<string, string>>(reader); 
                    foreach (var pair in typedDictionary) 
                        dictionary.Add(pair.Key, pair.Value); 
                } 
                break; 
 
            default: 
                throw new JsonSerializationException(string.Format("Unknown token {0} at path {1}", tokenType, reader.Path)); 
        } 
 
        return dictionary; 
    } 
 
    // Change to false if you want the dictionary written as an array of key/value objects. 
    public override bool CanWrite { get { return true; } } 
 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
        var dictionary = (StringDictionary)value; 
        writer.WriteStartObject(); 
        foreach (DictionaryEntry entry in dictionary) 
        { 
            writer.WritePropertyName((string)entry.Key); 
            writer.WriteValue((string)entry.Value); 
        } 
        writer.WriteEndObject(); 
    } 
} 
 
public static partial class JsonExtensions 
{ 
    public static JsonReader SkipComments(this JsonReader reader) 
    { 
        while (reader.TokenType == JsonToken.Comment && reader.Read()) 
            ; 
        return reader; 
    } 
} 

编写完成后,您将需要使用服务器端的转换器来反序列化传入的 JSON。您没有指定您正在使用哪个版本的 Web API。要全局添加转换器,请参阅

您可能还想在客户端使用转换器来序列化您的 JSON。如果这样做,您的内容参数将更紧凑地序列化为 JSON 对象,而不是键/值数组。 (转换器接受两种形式作为输入。)

fiddle 样本here .