ModelState错误-Newtonsoft.Json.JsonSerializationException:无法填充列表类型System.Net.TrackingStringDictionary

时间:2018-10-09 13:14:41

标签: c# .net asp.net-web-api json.net

尝试调用webApi时,标题中出现错误。 这是我的课程:

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;

这是一个杰森:

{"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控制器重现该错误:

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

还有一个在帖子调用者中的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小提琴通过以下方式演示了将上述JSON字符串直接反序列化为NotificationDTO时失败的情况:

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

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

1 个答案:

答案 0 :(得分:0)

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

因此,有必要编写一个System.Net.TrackingStringDictionary来反序列化此类型的对象或从该类型派生的对象:

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对象,而不是键/值数组。 (转换器接受两种形式的输入。)

提琴Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected