Как сериализовать / десериализовать .NET типизированный JSON в angular2 + - PullRequest
0 голосов
/ 17 мая 2018

Я звоню .NET Web Api с Angular клиента , и я использую JSON для сериализации / десериализации данных.

Я пытаюсь десериализовать объект Model , который содержит список Detector . Детектор - это абстрактный класс с двумя унаследованными потомками: TextDetector и ColorDetector .

Чтобы иметь возможность распознать, какой тип детектора должен быть создан во время десериализации, я установил TypeNameHandling.Auto для моего JsonSerializerSettings (сторона .NET).

Типичный ответ get для Модели, содержащей TextDetector

{
  "Detectors": {
    "$type": "System.Collections.Generic.HashSet`1[[I2D_Api.Models.Detector, I2D Api]], System.Core",
    "$values": [
      {
        "$type": "I2D_Api.Models.TextDetector, I2D Api",
        "Id": 1,
        "Name": "Detector0",
        "Bounds": "0, 0, 0, 0"
      }
    ]
  },
  "Id": 1,
  "Name": "Modèle 0",
  "ImgModelLink": "https://gamewave.fr/static/images/medias/upload/Fortnite/canards/Fortnite_20180515121231.jpg"
}

Но мне не нравится это решение (которое я даже не могу заставить работать), потому что оно предполагает, что я должен вручную вводить свои данные при каждом запросе на стороне клиента (Post или Put), чтобы правильно десериализовать сторону .NET. ... В дополнение к этому, мне еще не удалось десериализовать этот JSON в сторону объекта Model из-за префиксов $ (но это возможно, я думаю)

Я думаю, что я иду по неправильному пути, я ищу, но не могу найти другой способ передать эту коллекцию, и это кажется грязным. Есть ли другой способ сделать это?


Примечание : я использую EntityFramework, это мой метод get

[ResponseType(typeof(Model))]
public IHttpActionResult GetModel(int id)
{
    Model model = db.Models.Find(id);
    if (model == null)
    {
        return NotFound();
    }

    return Ok(model);
}

EDIT : Итак, я перешел по ссылке @dbc: Десериализация полиморфных классов json без информации о типе , что именно то, что я хочу. Я реализовал преобразователь Json, который знает, как создать дочерний класс на основе отсутствующего свойства Color (без свойства color = TextDetector, свойство color = ColorDetector).

Также заменил мое свойство Bounds ( JsonProperty.ValueProvider не удалось извлечь значение в структуре) на свойства X, Y, Width и Height в классе Detector (не проблема). Наконец изменилось TypeNameHandling на Объект .

Но теперь я получил исключение stackoverflow, которое я не понимаю. Обратите внимание, что TextDetector не имеет больше атрибутов / свойств , чем Detector Ошибки появляются из этой строки в моем DetectorConverter

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    JObject item = JObject.Load(reader); // This throw stackoverflow exception
    if (item["Color"] == null)
    {
        return item.ToObject<TextDetector>();
    }
    else
    {
        return item.ToObject<ColorDetector>();
    }
}

При первом ReadJson выполнении, без исключения. Но тогда это выглядит как JObject.load (reader) , вызывая внутренний цикл, который я не вижу в стеке, потому что это внешний код. Единственное, что я знаю, это то, что тип элемента после загрузки из считывателя - Детектор при первом выполнении, а затем TextDetector , зацикливание навсегда ..

1 Ответ

0 голосов
/ 18 мая 2018

Спасибо @dbc за указание в правильном направлении.

Десериализация полиморфных классов json без информации о типах с использованием json.net

Принятый ответ по этой ссылке является правильным ответом.


Некоторые точности, которые я хотел бы добавить:

  • Используя это решение, мне пришлось удалить struct свойства моего абстрактного класса, потому что convert не смог их прочитать (я думаю, что это возможно, но я предпочел вместо этого извлечь атрибуты struct в мой класс abtrast)
  • При чтении входящего Json может возникнуть исключение stackoverflow . Вы можете решить эту проблему, используя serializer.populate заменяя метод JObject toItem. ИЛИ, и это то, что я сделал, применил JSON NoConverter к классу дочерних элементов бетона

Класс NoConverter, который вы можете скопировать / вставить и использовать в качестве атрибута, как и любой другой JsonConverter

public class NoConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return false;
    }

    public override bool CanRead { get { return false; } }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
...