#c# #json #dynamic #json.net
#c# #json #динамический #json.net
Вопрос:
Я запрашиваю конечную точку REST для получения данных. Результатом может быть один из двух видов документов
В упрощенных версиях это
1.
{
"Feature": {
"CreationDate": "2018-07-12T09:22:37.068Z",
"_CreatedAt": "Jul 12, 2018",
"ObjectID": 236769828012,
"ObjectUUID": "5a4fa66b-a81b-48c3-afdc-b7ad8c4d4d1b",
"VersionId": "36",
}
}
{
"Initiative": {
"CreationDate": "2018-07-12T09:22:37.068Z",
"_CreatedAt": "Jul 12, 2018",
"ObjectID": 236769828012,
"ObjectUUID": "5a4fa66b-a81b-48c3-afdc-b7ad8c4d4d1b",
"VersionId": "36",
}
}
Таким образом, структура документов идентична — кроме первого свойства — чего я сейчас не делаю во время выполнения.
Мой вопрос:
Как мне получить значение для этого свойства?
Мой код для извлечения просто использует компонент Newtonsoft для десериализации результата из API в dynamic
конструкцию.
static void GetItemByProject(string projectId)
{
//var uri = ...;
response = GetData(uri);
dynamic itemData = JsonConvert.DeserializeObject(response.Result);
}
static async Task<string> GetData(string uri)
{
return await client.GetStringAsync(uri);
}
static readonly HttpClient client = new HttpClient();
Я знаю, что могу использовать отражение или преобразовать результат метода DeserializeObject в Dictionary<string, dynamic>
результат и перебирать ключи, но это кажется действительно громоздким.
Есть ли более элегантный способ сделать то, что я хочу?
Комментарии:
1. Просто FWIW, вам бы не повезло, если бы было второе свойство. JSON описывает объекты следующим образом: «Объект представляет собой неупорядоченный набор пар имя / значение». (JavaScript, с другой стороны, привнес в них порядок. JSON все еще не имеет и, вероятно, не будет.) Но поскольку вы имеете дело только с одним свойством, вы в хорошей форме. 🙂
2. @T.J.Crowder да, я знаю… но в моем случае я на 100% уверен, что второго свойства никогда не будет 🙂
3. Вы можете использовать
JObject
иJson.Linq
4. Если вам нужно иметь дело только с двумя именами свойств, у вас, вероятно, может быть класс-оболочка, в котором определены оба свойства. При десериализации только одно из двух свойств будет иметь значение. Вы также можете сделать два свойства закрытыми и добавить
[JsonProperty]
к обоим, а затем предоставить ненулевое свойство через общедоступное свойство. Это быстро реализуется, не уверен, что это элегантно .
Ответ №1:
Вы можете использовать Json.Linq
для этого просто получить первое свойство и десериализовать его значение
var result = JObject.Parse(response.Result);
var value = result.Properties().FirstOrDefault()?.Value.ToObject<Response>();
Где Response
класс может быть следующим (просто пример, вы можете использовать любую модель, которую хотите)
public class Response
{
public DateTime CreationDate { get; set; }
public string _CreatedAt { get; set; }
public long ObjectID { get; set; }
public string ObjectUUID { get; set; }
public string VersionId { get; set; }
}
Комментарии:
1. @JesperLundStocholm Отвечает ли это на ваш вопрос, вам нужны более подробные сведения или пояснения?
2. Привет, Павел, как упоминалось @Roman ниже, я хочу избежать создания классов-оболочек для обработки этого. Я ищу решение для прямой работы с ответом JSON 🙂
3. @JesperLundStocholm Что мешает вам использовать
JObject
свойства и значения напрямую?4. ничего … Мне нужно будет заглянуть в JObject, чтобы узнать, работает ли он для меня, так что спасибо за это предложение. Я просто хочу использовать его без необходимости поддерживать классы-оболочки в качестве класса «Response» выше 🙂
Ответ №2:
Предполагая, что мы имеем
public class Root
{
public FeatureOrInitiative Feature { get; set; }
public FeatureOrInitiative Initiative { get; set; }
public static Root FromJson(string json) => JsonConvert.DeserializeObject<Root>(json);
}
public class FeatureOrInitiative
{
[JsonProperty("CreationDate")]
public DateTimeOffset CreationDate { get; set; }
[JsonProperty("_CreatedAt")]
public string CreatedAt { get; set; }
[JsonProperty("ObjectID")]
public long ObjectId { get; set; }
[JsonProperty("ObjectUUID")]
public Guid ObjectUuid { get; set; }
[JsonProperty("VersionId")]
public long VersionId { get; set; }
}
На самом деле это оно. Мы просто вызываем наш десериализатор и получаем то, что нам нужно для обоих вариантов:
Root itemData = Root.FromJson(response.Result);
// Feature or Initiative is null
Комментарии:
1. Привет @Roman, я намеренно старался избегать использования C # DTO (классов-оболочек) для обработки этого. На данный момент я не знаю, какие свойства мне нужны, и не хочу также поддерживать класс-оболочку.