Как получить данные JSON в метод Web API ApiController?

Я пишу ApiController веб-API с несколькими методами PUT, которые получают данные JSON. JSON не является детерминированным и, следовательно, не может быть жестко сопоставлен с пользовательским объектом C#, но должен быть получен в виде словарей/последовательностей (карт/списков).

Я попытался использовать IDictionary для параметра данных метода PUT в контроллере, и это работает - данные отображаются из JSON в словарь. Однако необходимо объявить словарь как <String,Object>, и нет четкого способа получить значения Object как их соответствующие типы. (В ходе поиска я нашел несколько предложенных клугов, но это именно так.)

Существует также тип System.Json.JsonObject, который мне, наконец, удалось загрузить через NuGet, но когда я его использую, система, похоже, не знает, как сопоставлять данные.

Как это обычно делается? Как вы реализуете метод ApiController, который получает универсальный JSON?

Я вижу три основных подхода:

  1. Каким-то образом заставить Dictionary/Sequence работать с Object или чем-то подобным.
  2. Заставьте что-то вроде System.Json.JsonObject работать, возможно, прокручивая информацию о маршрутизации.
  3. Получите JSON в виде массива байтов, а затем выполните явный синтаксический анализ с помощью одного из доступных инструментов C# JSON.

(Что касается того, насколько динамичны данные, объекты JSON могут иметь отсутствующие записи или посторонние записи, а в некоторых случаях конкретная запись может быть представлена ​​либо как одно значение JSON, либо как массив значений JSON. (Где «значение» — это массив JSON. , объект, строка, число, логическое значение или нуль.) В общем, за исключением неоднозначности массив/не массив, отношение между ключами и типами значений известно.)

(Но я должен отметить, что это большой проект, и я буду получать строки JSON от нескольких других компонентов других авторов. Возможность проверить полученный тип и подтвердить, что он соответствует ожиданиям, была бы весьма полезна и, возможно, даже необходима. с точки зрения безопасности.)

(Должен добавить, что я относительный новичок в C# — работаю с ним всего около 6 месяцев.)


person Hot Licks    schedule 03.06.2014    source источник
comment
Вопрос должен быть более конкретным, как это обычно делается? вопросы о стиле обычно закрываются как слишком общие и/или основанные на мнении.   -  person JK.    schedule 04.06.2014
comment
Как dynamic вы получаете JSON? Знаете ли вы заранее, какие поля он может содержать?   -  person Yuval Itzchakov    schedule 04.06.2014
comment
Ну, я собирался предложить солидную награду за это, но, думаю, я не буду этого делать.   -  person Hot Licks    schedule 04.06.2014
comment
Я довольно хорошо понял это. Жаль, что никто не хочет знать, что я нашел.   -  person Hot Licks    schedule 05.06.2014
comment
@HotLicks, вопрос был открыт повторно, не стесняйтесь добавлять то, что вы нашли.   -  person Greg    schedule 11.06.2014
comment
@HotLicks Можете ли вы опубликовать свое решение? Я сталкиваюсь с аналогичной проблемой в контроллере API обратного вызова, который я пишу.   -  person Shiva    schedule 11.06.2014


Ответы (1)


Вы должны знать, какие данные вы ожидаете, но в прошлом я успешно делал это, используя динамическую типизацию.

Что-то вроде этого:

    [Test]
    public void JsonTester()
    {
        string json = "{ 'fruit':'banana', 'color':'yellow' }";

        dynamic data = JsonConvert.DeserializeObject(json);

        string fruit = data["fruit"];
        string color = data["color"];

        Assert.That(fruit == "banana");
        Assert.That(color == "yellow");
    }

Изменить.
Либо вам нужно заранее знать тип, который вы хотите десериализовать, — в этом случае вы можете немедленно десериализовать его в этот тип.
Или вы можете десериализовать его в тип dynamic , а затем преобразовать его в свой статический тип, как только вы поймете, что хотите с ним делать.

using Newtonsoft.Json;
using NUnit.Framework;

public class DTO
{
    public string Field1;
    public int Field2;
}

public class JsonDeserializationTests
{
    [Test]
    public void JsonCanBeDeserializedToDTO()
    {
        string json = "{ 'Field1':'some text', 'Field2':45 }";

        var data = JsonConvert.DeserializeObject<DTO>(json);

        Assert.That(data.Field1 == "some text");
        Assert.That(data.Field2 == 45);
    }

    [Test]
    public void JsonCanBeDeserializedToDynamic_AndConvertedToDTO()
    {
        string json = "{ 'Field1':'some text', 'Field2':45 }";

        var dynamicData = JsonConvert.DeserializeObject<dynamic>(json);
        var data = new DTO { Field1 = dynamicData["Field1"], Field2 = dynamicData["Field2"] };

        Assert.That(data.Field1 == "some text");
        Assert.That(data.Field2 == 45);
    }
}
person demoncodemonkey    schedule 03.06.2014
comment
Итак, как вы делаете динамическую типизацию? Примеры, которые я нашел, были просто вариациями Object kluges? - person Hot Licks; 04.06.2014
comment
Непонятно, как это будет работать в контексте ApiController, где фреймворк выполняет десериализацию. - person Hot Licks; 04.06.2014
comment
До сих пор не ясно, как это будет работать в ApiController. - person Hot Licks; 04.06.2014