Reputation:
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"
]
}
Upvotes: 147
Views: 381473
Reputation: 43
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.
Upvotes: 1
Reputation: 34810
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.
Upvotes: 79
Reputation: 3262
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
Upvotes: 286
Reputation: 81
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
Upvotes: 8
Reputation: 8490
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.
Upvotes: 2