2010-03-30 5 views
123

Я относительно новичок в работе с данными C# и JSON и ищу руководство. Я использую C# 3.0, с .NET3.5SP1 и JSON.NET 3.5r6.Десалиализация данных JSON на C# с использованием JSON.NET

У меня есть определенный класс C#, который мне нужно заполнить из структуры JSON. Однако не каждая структура JSON для записи, полученной из веб-службы, содержит все возможные атрибуты, которые определены в классе C#.

Я делаю то, что кажется неправильным, трудным и просто выбирает каждое значение по одному из объекта JObject и преобразует строку в требуемое свойство класса.

JsonSerializer serializer = new JsonSerializer(); 
var o = (JObject)serializer.Deserialize(myjsondata); 

MyAccount.EmployeeID = (string)o["employeeid"][0]; 

Каков наилучший способ десериализации структуру JSON в класс C# и обработки возможных недостающих данных из источника JSON?

Мой класс определяется как:

public class MyAccount 
    { 

    [JsonProperty(PropertyName = "username")] 
    public string UserID { get; set; } 

    [JsonProperty(PropertyName = "givenname")] 
    public string GivenName { get; set; } 

    [JsonProperty(PropertyName = "sn")] 
    public string Surname { get; set; } 

    [JsonProperty(PropertyName = "passwordexpired")] 
    public DateTime PasswordExpire { get; set; } 

    [JsonProperty(PropertyName = "primaryaffiliation")] 
    public string PrimaryAffiliation { get; set; } 

    [JsonProperty(PropertyName = "affiliation")] 
    public string[] Affiliation { get; set; } 

    [JsonProperty(PropertyName = "affiliationstatus")] 
    public string AffiliationStatus { get; set; } 

    [JsonProperty(PropertyName = "affiliationmodifytimestamp")] 
    public DateTime AffiliationLastModified { get; set; } 

    [JsonProperty(PropertyName = "employeeid")] 
    public string EmployeeID { get; set; } 

    [JsonProperty(PropertyName = "accountstatus")] 
    public string AccountStatus { get; set; } 

    [JsonProperty(PropertyName = "accountstatusexpiration")] 
    public DateTime AccountStatusExpiration { get; set; } 

    [JsonProperty(PropertyName = "accountstatusexpmaxdate")] 
    public DateTime AccountStatusExpirationMaxDate { get; set; } 

    [JsonProperty(PropertyName = "accountstatusmodifytimestamp")] 
    public DateTime AccountStatusModified { get; set; } 

    [JsonProperty(PropertyName = "accountstatusexpnotice")] 
    public string AccountStatusExpNotice { get; set; } 

    [JsonProperty(PropertyName = "accountstatusmodifiedby")] 
    public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; } 

    [JsonProperty(PropertyName = "entrycreatedate")] 
    public DateTime EntryCreatedate { get; set; } 

    [JsonProperty(PropertyName = "entrydeactivationdate")] 
    public DateTime EntryDeactivationDate { get; set; } 

    } 

И образец JSON для синтаксического анализа является:

{ 
    "givenname": [ 
     "Robert" 
    ], 
    "passwordexpired": "20091031041550Z", 
    "accountstatus": [ 
     "active" 
    ], 
    "accountstatusexpiration": [ 
     "20100612000000Z" 
    ], 
    "accountstatusexpmaxdate": [ 
     "20110410000000Z" 
    ], 
    "accountstatusmodifiedby": { 
     "20100214173242Z": "tdecker", 
     "20100304003242Z": "jsmith", 
     "20100324103242Z": "jsmith", 
     "20100325000005Z": "rjones", 
     "20100326210634Z": "jsmith", 
     "20100326211130Z": "jsmith" 
    }, 
    "accountstatusmodifytimestamp": [ 
     "20100312001213Z" 
    ], 
    "affiliation": [ 
     "Employee", 
     "Contractor", 
     "Staff" 
    ], 
    "affiliationmodifytimestamp": [ 
     "20100312001213Z" 
    ], 
    "affiliationstatus": [ 
     "detached" 
    ], 
    "entrycreatedate": [ 
     "20000922072747Z" 
    ], 
    "username": [ 
     "rjohnson" 
    ], 
    "primaryaffiliation": [ 
     "Staff" 
    ], 
    "employeeid": [ 
     "999777666" 
    ], 
    "sn": [ 
     "Johnson" 
    ] 
} 

ответ

70

Вы пробовали использовать общий метод DeserializeObject?

JsonConvert.DeserializeObject<MyAccount>(myjsondata); 

Любые недостающие поля в данных JSON должны быть просто пустыми.

UPDATE:

Если строка JSON массив, попробуйте следующее:

var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata); 

jarray должен затем быть List<MyAccount>.

ДРУГОЙ UPDATE:

вы получаете исключение не согласуется с массивом объекты- Я думаю, что сериализатору испытывает проблемы с Dictionary типизированных accountstatusmodifiedby собственности.

Попробуйте исключить из сериализации свойство accountstatusmodifiedby и посмотрите, поможет ли это. Если это так, вам может потребоваться представить это свойство по-разному.

Документация: Serializing and Deserializing JSON with Json.NET

+0

Спасибо. Однако я получаю сообщение об ошибке «Невозможно десериализовать массив JSON в тип« System.String ». когда он пытается десериализовать (например) массив заданного имени JSON в строку класса NameName. Атрибуты JSON, которые я определил как строку в классе C#, представляют собой только массивы одиночных элементов. Вот почему я начал собирать ценности один за другим, когда я столкнулся с проблемой такого рода во время процесса десериализации. Другая магия, которую я пропускаю? – 2010-03-30 15:18:42

+0

обновленный ответ ... –

+0

Итак ... 'DateTime AccountStatusExpiration' (например) не имеет значения NULL, как определено в коде. Что нужно сделать, чтобы сделать его недействительным? Просто измените 'DateTime' на' DateTime? '? –

8

Вы можете использовать:

JsonConvert.PopulateObject(json, obj); 

здесь: json является строка JSON, obj является целевым объектом.См: example

Примечание: PopulateObject() не стирать OBJ списка данных, после Populate(), obj's член списка будет содержит свои исходные данные и данные из JSON строки

+2

это PopulateObject - Population не находится в объектной модели. – amok

+0

Не работает в сложных объектах C#. – SutharMonil

+1

Это работало СОВЕРШЕННО для меня! У меня возникли проблемы, когда у меня была довольно сложная строка JSON, когда я попытался передать ее объектам C#, все, что помечено как «NotNull», было бы отсутствующим в объекте, даже если оно присутствовало в строке JSON для начала. Очень странно. Я использовал этот метод, и он работал PERFECT! – jward01

0

Предполагая, что ваши данные образца верны, ваше имя и другие записи, заключенные в скобки, являются массивами в JS ... вы захотите использовать List для этих типов данных. и List для say accountstatusexpmaxdate ... Я думаю, что вы, например, неверно отформатировали даты, поэтому не знаете, что еще неверно в вашем примере.

Это старый пост, но он хотел бы обратить внимание на проблемы.

1

Вы можете попробовать проверить некоторые генераторы классов в Интернете для получения дополнительной информации. Тем не менее, я считаю, что некоторые из ответов были полезны. Вот мой подход, который может быть полезен.

Следующий код был составлен с учетом динамического метода.

dynObj = (JArray)JsonConvert.DeserializeObject(nvm); 

     foreach (JObject item in dynObj) 
     { 
      foreach (JObject trend in item["trends"]) 
      { 
     Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]); 

      } 
     } 

Этот код в основном позволяет получить доступ к членам, содержащимся в строке Json. Просто по-другому, без необходимости в классах. query, trend и url - объекты, содержащиеся в строке Json.

Вы также можете использовать this website. Не доверяйте классам 100%, но вы получаете эту идею.

45

Ответ воспроизведен из https://stackoverflow.com/a/10718128/776476

Вы можете использовать тип C# dynamic, чтобы сделать вещи проще. Этот метод также упрощает повторный факторинг, поскольку он не полагается на магические струны.

Json

Строка json ниже простой ответ от вызова HTTP API, и это определяет два свойства: Id и Name.

{"Id": 1, "Name": "biofractal"} 

C#

Используйте JsonConvert.DeserializeObject<dynamic>() десериализовать эту строку в динамический тип, то просто доступ к его свойствам обычным способом.

var results = JsonConvert.DeserializeObject<dynamic>(json); 
var id = results.Id; 
var name= results.Name; 

Примечание: Ссылка NuGet для сборки NewtonSoft является http://nuget.org/packages/newtonsoft.json. Не забудьте добавить: using Newtonsoft.Json; для доступа к этим классам.

+5

Любите использование . Однако, мне пришлось сделать это, чтобы заставить его работать: result ["Id"]. Значение и результат ["Name"]. Значение – fredw

+0

Хотя динамика - хорошая альтернатива, приведенные выше примеры не используют «магические строки», а вместо этого используя сильно типизированные генерики, которые обновляются во время обычных методов рефакторинга VS (если только внутри представления в MVC, которое выходит за рамки этого вопроса). – gcoleman0828

+1

У вас все еще есть «магические струны», теперь они просто скрыты благодаря использованию динамических! –

3

Построение ответа bbant, это мое полное решение для десериализации JSON с удаленного URL-адреса.

using Newtonsoft.Json; 
using System.Net.Http; 

namespace Base 
{ 
    public class ApiConsumer<T> 
    { 
     public T data; 
     private string url; 

     public CalendarApiConsumer(string url) 
     { 
      this.url = url; 
      this.data = getItems(); 
     } 

     private T getItems() 
     { 
      T result = default(T); 
      HttpClient client = new HttpClient(); 

      // This allows for debugging possible JSON issues 
      var settings = new JsonSerializerSettings 
      { 
       Error = (sender, args) => 
       { 
        if (System.Diagnostics.Debugger.IsAttached) 
        { 
         System.Diagnostics.Debugger.Break(); 
        } 
       } 
      }; 

      using (HttpResponseMessage response = client.GetAsync(this.url).Result) 
      { 
       if (response.IsSuccessStatusCode) 
       { 
        result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings); 
       } 
      } 
      return result; 
     } 
    } 
} 

Usage будет, как:

ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script"); 

Где FeedResult класс генерируется с помощью Xamasoft JSON Class Generator

Вот скриншот настроек, которые я использовал, что позволяет странные имена свойств, которые web version не мог объяснить.

Xamasoft JSON Class Generator

1

Я нашел мой, я построил свой объект неправильно. Я использовал http://json2csharp.com/ для создания моего класса объектов из JSON. Как только у меня был правильный Oject, я смог бросить без проблем. Норбит, ошибка Нооба. Думал, что добавлю его, если у вас будет такая же проблема.