Ошибка ModelState - Newtonsoft.Json.JsonSerializationException: невозможно заполнить тип списка System.Net.TrackingStringDictionary - PullRequest
0 голосов
/ 09 октября 2018

У меня ошибка в заголовке при попытке вызвать 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;

Это 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)

Пример объекта

Попробуйте пример: Вы можете воспроизвести ошибку с помощью простого контроллера веб-API:

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

И Json, как это в Post Caller:

{"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 голосов
/ 10 октября 2018

Ваша настоящая проблема здесь в том, что ваш 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, а не как массив ключ / значение.(Преобразователь принимает обе формы в качестве входных данных.)

Пример скрипта здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...