Deserializing JSON data to C# using JSON.NET - c#

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

Use
var rootObject = JsonConvert.DeserializeObject<RootObject>(string json);
Create your classes on JSON 2 C#
Json.NET documentation: Serializing and Deserializing JSON with Json.NET

Have you tried using the generic DeserializeObject method?
JsonConvert.DeserializeObject<MyAccount>(myjsondata);
Any missing fields in the JSON data should simply be left NULL.
UPDATE:
If the JSON string is an array, try this:
var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);
jarray should then be a List<MyAccount>.
ANOTHER UPDATE:
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.
Documentation: Serializing and Deserializing JSON with Json.NET

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

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.

I found my I had built my object incorrectly. I used http://json2csharp.com/ to generate me my object class from the JSON. Once I had the correct Oject I was able to cast without issue. Norbit, Noob mistake. Thought I'd add it in case you have the same issue.

You can try checking some of the class generators online for further information. However, I believe some of the answers have been useful. Here's my approach that may be useful.
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 a 100% but you get the idea.

Assuming your sample data is correct, your givenname, and other entries wrapped in brackets are arrays in JS... you'll want to use List for those data types. and List for say accountstatusexpmaxdate... I think you example has the dates incorrectly formatted though, so uncertain as to what else is incorrect in your example.
This is an old post, but wanted to make note of the issues.

Related

Can't deserialize JSON into C# POCO

I can't convert JSON Object into C# class object I've tried many things but the same error pops up:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.List`1[CoderwallDotNet.Api.Models.Account]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.
I am using this JSON and tring to get the response in windows 8.1 application.
[
{
"id": 1,
"time": 40,
"srcLong": 35.909124,
"srcLat": 31.973628,
"destLong": 35.898258,
"destLat": 31.985622,
"subSites": [
{
"id": 1,
"name": "location1"
},
{
"id": 2,
"name": "location2"
},
{
"id": 3,
"name": "locaion3"
}
]
}]
and the I tried to read from the JSON using webclient but its not working it can't recognize it so I am using Newtonsoft.Json and I creted these class to get the response.
public class SubSite
{
public int id { get; set; }
public string name { get; set; }
}
public class RootObject
{
public int id { get; set; }
public int time { get; set; }
public double srcLong { get; set; }
public double srcLat { get; set; }
public double destLong { get; set; }
public double destLat { get; set; }
public List<SubSite> subSites { get; set; }
}
var serviceUri = "http://localhost:24728/api/sites";
var client = new HttpClient();
var response = await client.GetAsync(serviceUri);
var datafile = await response.Content.ReadAsStringAsyn();
List<RootObject> data = JsonConvert.DeserializeObject<List<RootObject>>(datafile);
test1234.Text = data.ToString();//i am trying to for eample destlat
but I can't get the value I am getting the response and everything is fine but idk how to put it into object and use it where ever I want. For example, I want to get the value of time and the other but I have problem with List of subsites or get the location inside the subsites or srclong or srclat and here is the project how to get the Json to c# object:
https://onedrive.live.com/?cid=e648f5a0f179f346&id=E648F5A0F179F346%218429&ithint=folder,rar&authkey=!ALKlJdwsb8ER2FA
This works fine:
var data = JsonConvert.DeserializeObject<RootObject>(datafile)
You can deserialize into a dynamic object if you are not too particular about losing intellisense. One advantage to using a dynamic is that you don't have to create classes just to be able to deserialize and also that you don't need to update your class structures if the returned data has changed. As an example you can do this:
dynamic jsonValue = JsonConvert.DeserializeObject(jsonData);
foreach (dynamic rootObject in jsonValue)
{
theData.destLong.Value <-- use it anyway you want, store in a variable, etc.
// to get to each of the subSite in the rootObject
foreach (dynamic subSite in rootObject.subSites)
{
subSite.id.Value <-- returns an int based on your data
subSite.name.Value <-- returns a string based on your data
}
}
// where jsonData constains the json string you posted
The foreaeach is important because the data you posted will result into an array. You can also just do a jsonValue[0] but watch out for errors for null values, which you should be checking anyway starting with the returned json string.

HttpClient ObjectContent JSON: format with root class name in json object?

I generate a C# class for a json source using json2csharp.com. My json is:
{
"email_verified": true,
"user_id": "gg2323",
"app_metadata": {
"tc_app_user": {
"user_guid": "c0fb150f6er344df98ea3a06114e1e4a",
"cto_admin_a_user_id": "551294d4f6cfb46e65a5aq71",
"lang": "EN",
"country": "USA",
"disabled": false
}
and my resulting C# is:
public class TcAppUser
{
public string user_guid { get; set; }
public string cto_admin_a_user_id { get; set; }
public string lang { get; set; }
public string country { get; set; }
public bool disabled { get; set; }
}
public class AppMetadata
{
public TcAppUser tc_app_user { get; set; }
public int logins_count { get; set; }
}
public class RootObject
{
public bool email_verified { get; set; }
public string user_id { get; set; }
public AppMetadata app_metadata { get; set; }
}
Using the .NET HttpClient GET, I can read into this C# structure from the JSON API quite nicely. Going the other way (POST, PATCH) poses a problem: my app_metadata property name is dropped in the generated JSON output when I use a common approach like:
//Would be nice: var contentIn = new ObjectContent<string>(RootObjectInstance.app_metadata, new JsonMediaTypeFormatter());
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" + user_id, new StringContent(json, Encoding.UTF8, "application/json"));
The resulting JSON is now:
{
"tc_app_user": {
"lang": "en-en",
"country": "GER",
"disabled": false
}
}
My quick hack is to use the following additional wrapper to dynamically repackage the app_metadata property so it has the same format going out that it had coming in. The rest remains the same as above:
dynamic wireFormatFix = new ExpandoObject();
wireFormatFix.app_metadata = usr.app_metadata;
string json = JsonConvert.SerializeObject(wireFormatFix);
Now my JSON output corresponds to the JSON input. My question: what is best-practice to achieve symmetric json input and output here without a pesky format fix?
EDIT: If I try to PATCH the entire structure (RootObjectInstance instead of RootObjecInstance.app_metadata) I get:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Payload validation error: 'Additional properties not allowed: 'user_id'."
}
So, I must either send the app_metadata subset/property of the C# RootObject, properly packaged, or I must selectively delete fields from the RootObject to meet the API's requirements.
Thanks!
The root app_metadata tag is being removed from your JSON because you're simply not serializing it. This:
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);
Will serialize everything that is inside app_metadata.
If you serialized the entire object graph, you wouldn't need to patch anything:
string json = JsonConvert.SerializeObject(RootObjectInstance);
As a side note, you should follow C# naming conventions. You can use JsonProperty to help you with that.
Edit:
Ok, after your edit i see the actual problem. You're calling an API by user_id in your query string, and you also have a user_id property inside your object. This seems like you need two different objects for the job.
You have a couple of possibilities:
Create an object hierarchy:
public class BaseObject
{
[JsonProperty(email_verified)]
public bool EmailVerified { get; set; }
[JsonProperty(app_metadata)]
public AppMetadata AppMetadata { get; set; }
}
public class ExtendedObject : BaseObject
{
[JsonProperty(user_id)]
public string UserId { get; set; }
}
And then use the base type to serialize the data:
var baseObj = new BaseObject(); // Fill the object properties.
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" +
user_id,
new StringContent(json,
Encoding.UTF8,
"application/json"));
Use an anonymous object which includes only properties you actually need:
var intermidiateObj = new { app_metadata = usr.app_metadata };
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" +
user_id,
new StringContent(json,
Encoding.UTF8,
"application/json"));

Deserializing nested JSON arrays using RestSharp

I'm trying to deserialize the following JSON response using RestSharp. I have tried various model structures to extract the data to no avail. I keep getting tripped up on the nested arrays.
I do not have control over the service, so I can't change the format.
JSON Format:
[
{
"results": 19,
"statuscode": 200,
},
[
{
"id": 24,
"name": "bob"
},
{
"id": 82,
"name": "alice"
}
]
]
Using this model, I've been able to pull the data from the first object, but that's all. I'm not sure how exactly to read through the array that comes after the object.
public class Info
{
public int results { get; set; }
public int statuscode { get; set; }
}
Example deseralization:
var deserializer = new JsonDeserializer();
var wat = deserializer.Deserialize<List<List<Info>>>(response);
Am I just completely missing something here or are my only options to write a custom deserializer and/or use something like JSON.NET?
The problem is that your JSON array is exceptionally polymorphic: its first element is an object, and its second element is an array of objects. A more natural way to represent this would have been as a JSON object with two named properties -- but that's not what you have been given. Deserializing this directly to a c# POCO with two named properties in a single step with any serializer is going to be tricky since the JSON data model is quite different than your desired data model. Instead, it may be easiest to deserialize to an intermediate representation and convert. Luckily RestSharp has appropriate intermediate classes JsonObject and JsonArray.
Thus, if you want to deserialize to the following classes:
public class Info
{
public int results { get; set; }
public int statuscode { get; set; }
}
public class IdAndName
{
public int id { get; set; }
public string name { get; set; }
}
public class ResponseContent
{
public Info Info { get; set; }
public List<IdAndName> Data { get; set; }
}
You can do:
var array = (JsonArray)SimpleJson.DeserializeObject(response.Content);
var responseContent = (array == null ? (ResponseContent)null : new ResponseContent()
{
Info = array.OfType<JsonObject>().Select(o => SimpleJson.DeserializeObject<Info>(o.ToString())).FirstOrDefault(),
Data = array.OfType<JsonArray>().SelectMany(a => SimpleJson.DeserializeObject<List<IdAndName>>(a.ToString())).ToList()
});

Questioning received JSON structure

I'm currently using a beta API (http://developer.riotgames.com/api/methods) which returns JSON for all the exposed methods.
I've been able to use JSON.NET to deserialize all of these return values so far. However, today I consumed one of their function which returns a JSON that is valid but is in my opinion not correct.
You're probably wondering, why don't you ask it on the beta forum? I have but I haven't received an answer so far and in general this intrigues me.
A snippet of the JSON return:
"1001": {
"name": "Boots of Speed",
"plaintext": "Slightly increases Movement Speed",
"group": "BootsNormal",
"description": "<...
}
The problem I have with this structure is that the ID is used as a "group" without an identifier. I would be able to use this decently if it had
"ItemID" : "1001"
But it doesn't have that. I don't mind manually parsing it but I'd first like to know whether or not this JSON is correct (not just valid).
Do you agree that this is not a clean way of creating a JSON block that contains a list of elements or am I missing something here? So far I haven't seen any comments on the beta forum of this API so I'm really wondering why.
Edit "valid" vs "correct/usable":
I know it's a valid JSON statement. I'm questioning the fact whether this is usable with JSON.NET.
I have the following class definition (with two subclasses):
public class JSONItem
{
[JsonProperty("tags")]
public string[] Tags { get; set; }
[JsonProperty("plaintext")]
public string Plaintext { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("into")]
public string[] Into { get; set; }
[JsonProperty("image")]
public JSONItemImage Image { get; set; }
[JsonProperty("colloq")]
public string Colloq { get; set; }
[JsonProperty("gold")]
public JSONItemGold Gold { get; set; }
}
When giving the above JSON block to to JSONConvert.DeserializeObject(json) it throws an error because "1001" is not mentioned in JSONItem.
How do you handle this so that you can use JSON.NET?
A class like this won't work because you have no names to give the properties:
public class JSONItemWrapper
{
[JsonProperty("")]
public string ID { get; set; }
[JsonProperty("")]
public JSONItem MyProperty { get; set; }
}
Edit: "consistent with other methods"
The other methods return blocks where every property is within {} and has an identifier. The most recently added function have this "primary key outside of {}" style.
It is a valid json and you can use a type like Dictionary<string, SomeObject> to deserialize your json.
string json = #"{
""1001"": {
""name"": ""Boots of Speed"",
""plaintext"": ""Slightly increases Movement Speed"",
""group"": ""BootsNormal"",
""description"": ""desc...""
}
}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, MyObject>>(json);
and accesing an item later on by its key can be fast too.
public class MyObject
{
public string name { get; set; }
public string plaintext { get; set; }
public string group { get; set; }
public string description { get; set; }
}
It's annoying when APIs do things like this (using numbers as property names), but all is not lost. Simply deserialize the JSON using Json.NET and then access each of the items using the indexer operator on the parent object.
EDIT:
I almost never create DTOs when deserializing JSON. It's lots of unnecessary boilerplate in most cases. I prefer deserializing to a dynamic object, but that won't be as effective when dealing with property names that begin with digits.
Here is how I would deserialize your sample message:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonExample
{
internal class Program
{
private static void Main()
{
const string json = #"
{
'1001': {
'name': 'Boots of Speed',
'plaintext': 'Slightly increases Movement Speed',
'group': 'BootsNormal',
'description': '<...'
}
}";
var jObject = JsonConvert.DeserializeObject<JObject>(json);
var plaintext = jObject["1001"]["plaintext"].Value<string>();
Console.WriteLine(plaintext);
}
}
}
When put into http://JSONLint.com,
{
"1001": {
"name": "Boots of Speed",
"plaintext": "Slightly increases Movement Speed",
"group": "BootsNormal",
"description": "<..."
}
}
Validates as JSON.

Parsing JSON data in C#

I have a JSON data as follows
{"id": "367501354973","from": {
"name": "Bret Taylor",
"id": "220439" }
which is returned by an object(result) of IDictionary[String, Object]
In my C# code:
I have made a class for storing the JSON value which is as follows
public class SContent
{
public string id { get; set; }
public string from_name { get; set; }
public string from_id { get; set; }
}
My main C# function which stores the parses the JSON data and stores the value inside the class properties is as follows:
List<object> data = (List<object>)result["data"];
foreach (IDictionary<string, object> content in data)
{
SContent s = new SContent();
s.id = (string)content["id"];
s.from_name = (string)content["from.name"];
s.from_id = (string)content["from.id"];
}
When i execute this code, i get an exception saying System cannot find the Key "from.name" and "from.id"
When i comment the two lines (s.from_name = (string)content["from.name"];s.from_id = (string)content["from.id"];) my code runs fine.
I think i am not able to refer the nested JSON data properly.
Can anyone just validate it and please tell me how to refer nested data in JSON in C#?
Thanks
I'm not sure how you are parsing the JSON string. Are you using a class in the Framework to do the deserialization?
You could use the JavaScriptSerializer Class defined in the System.Web.Script.Serialization Namespace (you may need to add a reference to System.Web.dll)
Using that class, you would write your code like this:
public class SContent
{
public string id { get; set; }
public SFrom from { get; set; }
}
public class SFrom
{
public string name { get; set; }
public string id { get; set; }
}
Then deserialization looks like this:
var json = new JavaScriptSerializer();
var result = json.Deserialize<SContent>(/*...json text or stream...*/);
See JavaScriptSerializer on MSDN. You might also want to check out this similar question.

Categories