147

I'm relatively new to working with C# and JSON data and am seeking guidance. I'm using C# 3.0, with .NET3.5SP1, and JSON.NET 3.5r6.

I have a defined C# class that I need to populate from a JSON structure. However, not every JSON structure for an entry that is retrieved from the web service contains all possible attributes that are defined within the C# class.

I've been being doing what seems to be the wrong, hard way and just picking out each value one by one from the JObject and transforming the string into the desired class property.

JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);
MyAccount.EmployeeID = (string)o["employeeid"][0];

What is the best way to deserialize a JSON structure into the C# class and handling possible missing data from the JSON source?

My class is defined as:

 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; }
 }

And a sample of the JSON to parse is:

{
 "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"
 ]
}
Govind Malviya
13.8k17 gold badges70 silver badges95 bronze badges
asked Mar 30, 2010 at 14:49
0

5 Answers 5

286

You can create your C# classes at https://json2csharp.com, and then use this line of code with Json.NET:

var rootObject = JsonConvert.DeserializeObject<RootObject>(string json);

Json.NET documentation: Serializing and Deserializing JSON with Json.NET

TylerH
21.2k83 gold badges83 silver badges120 bronze badges
answered Jan 27, 2012 at 18:36

2 Comments

Visual Studio also has a Paste JSON as Classes option in the Edit-Paste Special menu.
This is a good solution to get a class type as a variable, but not much help in getting the actual data from that variable. It is probably more suitable as a comment than as an answer.
79

Have you tried using the generic DeserializeObject method from Newtonsoft's Json.NET?

JsonConvert.DeserializeObject<MyAccount>(myjsondata);

Any missing fields in the JSON data should simply be left NULL.

If the JSON string is an array, try this:

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

jarray should then be a List<MyAccount>.

The exception you're getting isn't consistent with an array of objects- I think the serializer is having problems with your Dictionary-typed accountstatusmodifiedby property.

Try excluding the accountstatusmodifiedby property from the serialization and see if that helps. If it does, you may need to represent that property differently.

TylerH
21.2k83 gold badges83 silver badges120 bronze badges
answered Mar 30, 2010 at 15:03

2 Comments

Thanks. However I get an error of "Cannot deserialize JSON array into type 'System.String'." when it's trying to deserialize (for example) the JSON givenname array into the class GivenName string. The JSON attributes that I have defined as string in the C# class are only ever single element arrays. This is why I started picking out the values one by one as I ran in to this kind of issue during the deserialize process. Other magic that I am overlooking?
So ... DateTime AccountStatusExpiration (for instance) is not nullable as defined in the code. What would it take to make it nullable? Simply change DateTime to DateTime??
8

You can use:

JsonConvert.PopulateObject(json, obj);

here: json is the json string,obj is the target object. See: example

Note: PopulateObject() will not erase obj's list data, after Populate(), obj's list member will contains its original data and data from json string

SimplyInk
7,0121 gold badge21 silver badges28 bronze badges
answered Dec 22, 2011 at 16:25

Comments

2

Building off of bbant's answer, this is my complete solution for deserializing JSON from a remote 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 would be like:

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

Where FeedResult is the class generated using the Xamasoft JSON Class Generator

Here is a screenshot of the settings I used, allowing for weird property names which the web version could not account for.

Xamasoft JSON Class Generator

answered Jul 31, 2014 at 15:58

1 Comment

This is... totally different code for totally different data and a totally different method of accessing that data. How is this useful for OP?
1

The following code was made with a dynamic method in mind:

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"]);
 }
}

This code basically allows you to access members contained in the Json string. Just a different way without the need of the classes. query, trend and url are the objects contained in the Json string.

You can also use this website. Don't trust the classes 100%, but you'll get the idea for how classes should be created.

TylerH
21.2k83 gold badges83 silver badges120 bronze badges
answered Sep 4, 2012 at 14:42

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.