Deserialize JSON Web Response in C# - c#

I am working with a REST API and getting an HTTP response in JSON format. The JSON string contains an object as the first and only "top-level" or "root-level" key with an array of objects as its value.
Ultimately, I need to pass each of the objects in the array to a SQL query, which I intend to do by creating a List and iterating over the List with a foreach loop.
Here's a sample of the JSON response:
{
"blueplates": [
{
"Appetizer": 26,
"Salad": 21,
"Soup": "SheCrab",
"Entree": 6434,
"Side": 2303093,
"Desert": 0,
"Beverage": "Sweet Tea + SoCo"
},
{
"Appetizer": 27,
"Salad": 21,
"Soup": "Tomato Bisque",
"Entree": 6434,
"Side": 2303093,
"Desert": 0,
"Beverage": "Lemonade + Rum"
},
{
"Appetizer": 28,
"Salad": 21,
"Soup": "Peanut",
"Entree": 6434,
"Side": 2303093,
"Desert": 0,
"Beverage": "Ginger Ale + Whiskey"
}
]
}
The approach that I am taking is to create two classes (consistent with the result that I've gotten from http://json2csharp.com/) - a RootObject class and a Blueplate class.
The classes are structured like so:
public class Blueplate
{
public int Appetizer { get; set; }
public int Salad { get; set; }
public string Soup { get; set; }
public int Entree { get; set; }
public int Side { get; set; }
public int Desert { get; set; }
public string Beverage { get; set; }
}
public class RootObject
{
public List<Blueplate> blueplates { get; set; }
}
I am using the JavaScriptSerializer class from the System.Web namespace. I've tried to manually re-format the JSON in order to validate my basic usage of JavaScriptSerializer, so the following code compiles and writes the value of the "Appetizer" key to the console, awaiting keyboard input after each value is displayed:
var response = "[{\"Appetizer\":26,\"Salad\":21,\"Soup\":\"SheCrab\",\"Entree\":6434,\"Side\":2303093,\"Desert\":0,\"Beverage\":\"Sweet Tea + SoCO\"}, {\"Appetizer\":27,\"Salad\":21,\"Soup\":\"Tomato Bisque\",\"Entree\":6434,\"Side\":2303093,\"Desert\":0,\"Beverage\":\"Lemonade + Rum\"}, {\"Appetizer\":28,\"Salad\":21,\"Soup\":\"Peanut\",\"Entree\":6434,\"Side\":2303093,\"Desert\":0,\"Beverage\":\"Ginger Ale + Whiskey\"}]";
JavaScriptSerializer deSerializedResponse = new JavaScriptSerializer();
List<Blueplate> blueplates = (List<Blueplate>)deSerializedResponse.Deserialize(response, typeof(List<Blueplate>));
for (int i = 0; i < blueplates.Count; i++)
{
Console.WriteLine(blueplates[i].Appetizer);
Console.ReadLine();
}
The problem that I am having is dealing with the root tag and making use of the RootObject class.
I've tried using variations of statements like the following, along with variations of for and foreach loops:
RootObject rootObject = (RootObject) deSerializedResponse.Deserialize(response, typeof(RootObject));
Apparently, I am confused on several points:
Mapping the root JSON object to the C# RootObject class
Mapping the objects in the root JSON object's array value to the C# Blueplate class, OR
Mapping the objects in the root JSON object's array value to the blueplates property of the RootObject class
Enumerating and looping over the blueplates property of the RootObject class
Casting or converting the object type returned by the Deserialize method as a List of Blueplate objects
Finally, please note that I wish to use native Microsoft assemblies, rather than third-party packages like JSON.NET. I understand that JSON.NET may perform better, and I've read a number of posts that emphasize JSON.NET's ease of use. If you would insist on JSON.NET, please enlighten on me how JSON.NET is handling the root object.
Still, the accepted answer will address a native solution. The question is:
how can I use the native Microsoft class JavaScriptSerializer to deserialize a JSON response with a root object that has an array of objects as its value, where the target values are the objects in the array, to pass a List to a SQL query?

The first Json does work with my test:
Edit: changed to foreach.
var response = "{blueplates :[{\"Appetizer\":26,\"Salad\":21,\"Soup\":\"SheCrab\",\"Entree\":6434,\"Side\":2303093,\"Desert\":0,\"Beverage\":\"Sweet Tea + SoCO\"}, {\"Appetizer\":27,\"Salad\":21,\"Soup\":\"Tomato Bisque\",\"Entree\":6434,\"Side\":2303093,\"Desert\":0,\"Beverage\":\"Lemonade + Rum\"}, {\"Appetizer\":28,\"Salad\":21,\"Soup\":\"Peanut\",\"Entree\":6434,\"Side\":2303093,\"Desert\":0,\"Beverage\":\"Ginger Ale + Whiskey\"}]}";
JavaScriptSerializer deSerializedResponse = new JavaScriptSerializer();
RootObject root = (RootObject)deSerializedResponse.Deserialize(response, typeof(RootObject));
foreach (Blueplate plate in root.blueplates)
{
Console.WriteLine(plate.Appetizer);
Console.ReadLine();
}

RootObject objRootObject = new RootObject();
HttpResponseMessage apioresponse = { "blueplates": [ Your response] } ;
string responseString = await apioresponse.Content.ReadAsStringAsync();
objRootObject = JsonConvert.DeserializeObject<RootObject>(responseString);

Related

Json is not deserializing correctly into a class

I'm trying to convert an array into a class. So I get the array, then serialize it with JsonConvert as you can see below:
var gameResponse = GetGame(Id);
var returnedArray = gameResponse.Result.Results;
var json = JsonConvert.SerializeObject(returnedArray);
var result = JsonConvert.DeserializeObject<T>(json);
I can see the results of this in Visual Studio debug mode and "json" looks like this:
[
{
\"CreatorId\":\"41c5321e-6f37-4d4f-92f7-fc381be0fc62\",
\"GameId\": \"3938\",
\"Type\": \"2\",
\"CreateDate\": \"1/2/2017\",
\"TeamId\": \"2394\",
\"LeaderId\": \"34922\",
\"CountryCode\": \"23\",
\"SalesRank\": \"4\",
\"Title\": \"Space Shooter Max\",
\"TeamName\": \"The One\",
\"TeamMembers\" : \"4\"
}
]
However, when the code hits the next line:
var result = JsonConvert.DeserializeObject<T>(json); // In this case, <T> is <Game>
I get this error:
JsonSerializationException: Cannot deserialize the current JSON array
(e.g. [1,2,3]) into type 'GameLabs.Game' because the type requires a
JSON object (e.g. {"name":"value"}) to deserialize correctly.
GameLabs.Game is a class that looks like this:
public sealed class Game
{
public string CreatorId { get; set; }
public string GameId { get; set; }
public string Title { get; set; }
public DateTime CreateDate { get; set; }
public string CountryCode { get; set; }
}
I'm not sure why it won't accept the JSON.
Does anyone see anything wrong?
Thanks!
If you examine your JSON, it is not an a single object, but instead a collection. "[..]" signifies a collection.
For example,
[ "Ford", "BMW", "Fiat" ]
The above Json implies a array of string with 3 elements. This is similar to your Json as well.
Hence you need to deserialize your Json to a Collection as well.
var result = JsonConvert.DeserializeObject<List<T>>(str);
You can read more on Json Arrays here
As I can see, your JSON is array and you should write somethink like this:
var result = JsonConvert.DeserializeObject<T[]>(json);
T=>T[]

Deserialize JSON string in to multiple C# objects

I have a JSON string in below format for which I want to deserialize it into C# List. But the record number "1","2","3" (it can be upto 1,2,3...n depends on the json response each time) in JSON restricting me to deserialize it into C# object using Newtonsoft.Json
{
"1":{
"UID":"1",
"LICENCENO":"licenseno",
"NAME":"ABC"
},
"2":{
"UID":"2",
"LICENCENO":"licenseno",
"NAME":"PQR"
},
"3":{
"UID":"3",
"LICENCENO":"licenseno",
"NAME":"XYZ"
}
}
I am using below code for deserialization
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<DriverMaster>>(json);
I have DriverMaster class created as-
public class DriverMaster
{
public string UID { get; set; }
public string LICENCENO { get; set; }
public string NAME { get; set; }
}
Deserialization line giving unhandled exception, I know I am doing it in wrong way, because DriverMaster json object cannot be extracted into c# directly without doing something to record number 1,2,3...n in c#. Can anyone please help me to sort it out? Thanks in advance.
You were close:
var result = JsonConvert.DeserializeObject<Dictionary<string, DriverMaster>>(json)
.Select(x => x.Value)
.ToList();
Solution.
Change your code to use...
var result = JsonConvert.DeserializeObject<Dictionary<int, DriverMaster>>(json);
Explaination
The type is not the same... The List<DriverMaster>type will convert to JSON like so...
{
"1":
{
"DriverMaster": {
"UID":"1",
"LICENCENO":"licenseno",
"NAME":"ABC"
}
}
}
This doesn't match what you showed in your question...
The type that you are looking for is actually Dictionary<int, DriverMaster>, which is a key/value pair which will output a JSON string like so
{
"1": { ... },
"2": { ... },
"3": { ... }
}
In order to fix that, you need to use the Dictionary<int, DriverMaster> type instead.
For these types of things I like to use the often overlooked feature of JToken.SelectTokens. This function allows you to select tokens within a json string and permits the use of wildcards.
Here's some code that will deserialize your sample by selecting past the 1,2,3...N in the json:
public static IEnumerable<DriverMaster> Deserialize(string json)
{
return JToken.Parse(json).SelectTokens("*")
.Select(jToken => jToken.ToObject<DriverMaster>());
}
The * basically says to select all tokens after the root, so it's selecting the values associated with 1, 2, 3.. etc... Here's another SO answer that shows a more complicated usage of the SelectTokens method.
You need to use
public class DriverMaster
{
public string UID { get; set; }
public string LICENCENO { get; set; }
public string NAME { get; set; }
}
public class Root
{
[JsonExtensionData]
public IDictionary<string,JToken> Data {get;set;}
}
and
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<Root>(json);
If you want to have result as List, you can parse the result as.
var list = new List<DriverMaster>();
foreach(KeyValuePair<string, JToken> token in result.Data)
{
list.Add(token.Value.ToObject<DriverMaster>());
}
That would give you the desired result as
1 licenseno ABC
2 licenseno PQR
3 licenseno XYZ

Assign values to dynamic number of sub-classes before serializing to JSON

I am integrating with a courier that requires me to pass box dimensions for each box in my consignment to their API in JSON format. I am able to set individual properties like RecipientName, but am not sure how to pass the box details for the varying number of boxes for each consignment.
The JSON needs to look like this (example is for a 2 box consignment):
{
"RecipientName": "Joe Bloggs",
"Packages" : [{
"boxNumber": "1",
"boxHeight": 1.55,
"boxLength": 1.55,
"boxWidth": 1.55
},
{
"boxNumber": "2",
"boxHeight": 2.55,
"boxLength": 2.55,
"boxWidth": 2.55
}]
}
I have built 2 classes, one that describes the structure of the JSON, and another that contains the method to serialize the JSON.
My JSON structure class looks like this (I have used a List because I have read that arrays are a fixed length, and because the number of boxes with vary I cannot use arrays):
public class API_JSON
{
public class Rootobject
{
public string RecipientName { get; set; }
public List<Package> Packages { get; set; }
}
public class Package
{
public string boxNumber { get; set; }
public double boxHeight { get; set; }
public double boxLength { get; set; }
public double boxWidth { get; set; }
}
}
And my API methods class looks like this:
public class API_Methods
{
public string recipientName;
public List<string> boxnumber;
public List<double> boxHeight;
public List<double> boxLength;
public List<double> boxWidth;
public Boolean SubmitConsignment(out string JSONData)
{
var NewRequestObject = new API_JSON.RootObject
{
Recipient = recipientName,
Packages = new API_JSON.Package
{
foreach (string item in ContainerNumber)
{
boxNumber=???,
boxHeight=???,
boxLength???=,
boxWidth=???
}
}
}
string JSONData = JsonConvert.SerializeObject(NewRequestObject);
return true;
}
}
I am then instantiating the object, setting its public variables, then running the method list this:
API_Methods myObject = new API_Methods();
myObject.recipientName;
myObject.boxnumber.Add(1);
myObject.boxnumber.Add(2);
myObject.boxHeight.Add(1.55);
myObject.boxHeight.Add(2.55);
myObject.boxLength.Add(1.55);
myObject.boxLength.Add(2.55);
myObject.boxWidth.Add(1.55);
myObject.boxWidth.Add(2.55);
bool test = API_Methods.SubmitConsignment(out JSON);
My problem is with the foreach loop - I know the code is incomplete - but I was hoping to iterate through the lists, but even with an empty foreach loop it appears to be the wrong place to put the loop as I start getting syntax errors about an expected "}"
You're actually overcomplicating this for yourself - create complete package objects, and add them to the List Packages, and then pass the rootobject to the serializer.
The error you are getting is because you are not correctly initializing / filling your Packages List. Your object is invalid, hence the serializer is throwing exceptions.
This will be a lot easier for you if you create some constructors for your objects, something like this:
public Package(number, height, length, width)
{
boxNumber = number;
boxHeight = height;
//rest of your properties here in same format
}
You can then also make your setters private in the class, if you wish.
You can then easily create your package objects:
var package1 = new Package(10, 10, 10, 10);
This should make it a lot easier to create your list of boxes to put in your rootObject.
You can add each package to the packages list (individually or within a foreach loop):
Packages.Add(package1)
Or you could even start getting more concise:
Packages.Add(new Package(10,10,10,10));
You want to separate your concerns more to help keep this clear - so I'd recommend you fully construct your rootObject, add the packages to the list in one class (your 3rd code snippet), and then serialize it another (your 2nd code snippet).
Edit:
I think you'd find it easier to refactor your code somewhat:
1) Have a public rootobject in your Json_Api class, with get; set;. Get rid of the box collections. Get rid of your foreach loop from here too.
public class API_Methods
{
public rootObject RootObject { get; set; }
public Boolean SubmitConsignment(out string JSONData)
{
string JSONData = JsonConvert.SerializeObject(NewRequestObject);
return true;
}
}
2) Set the properties of this rootobject outside this class (where you currently initialize your objects). Add the New Package()s to Packages list here too.
API_Methods myObject = new API_Methods();
myObject.RootObject.recipientName = "NAME";
myObject.RootObject.Packages.Add(new Package(10,10,10,10);
myObject.RootObject.Packages.Add(new Package(20,20,20,20);
bool test = API_Methods.SubmitConsignment(out JSON);
3) Call the API method next, it should return a serialized version of the wholerootobject, including your packages.
Just a side note, it would be more conventional to send the RootObject as a parameter to the API, and return the Json string object back.

How to map json and skip parent property?

I have this json string, which contains two elements each with a Number and a Status:
var jsonString = "{\"Errors\":[{\"Number\":9,\"Status\":\"BadRequest\"}, {\"Number\":3,\"Status\":\"BadConnection\"}]}";
As you see it has a parent property called Errors.
I have prepared this model:
public class ExceptionStructure
{
public int Number { get; set; }
public string Status { get; set; }
}
Using NewtonSoft.Json I would like to deserialize the json string into an array of ExceptionStructure objects, without also having to create a model for the parent property (as I don't really need it).
Can I do this (perhaps with some json attribute on the model class)?
I was hoping to do something like this to deserialize:
var exceptionArr = JsonConvert.DeserializeObject<ExceptionStructure>(jsonString);
JSON.NET allows you to deserialize parts of a json file. You can do this by first deserialzing the json string to a JObject, extract the relevant parts, and then deserialize those to your actual object.
JObject errors = JObject.Parse(jsonString);
IList<JToken> results = errors["Errors"].Children().ToList();
IList<ExceptionStructure> exceptions = new List<ExceptionStructure>();
foreach (JToken result in results)
{
ExceptionStructure exception= result.ToObject<ExceptionStructure>();
exceptions.Add(exception);
}
Honestly though, in your case it might be easier to just build a Errors parent class
More information can be found at http://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
this is may be helpful you.
string s = "{\"Errors\":[{\"Number\":9,\"Status\":\"BadRequest\"}, {\"Number\":3,\"Status\":\"BadConnection\"}]}";
var jobj = JObject.Parse(s);
List<ExceptionStructure> list = jobj["Errors"].ToObject<List<ExceptionStructure>>();
OR:
string s = "{\"Errors\":[{\"Number\":9,\"Status\":\"BadRequest\"}, {\"Number\":3,\"Status\":\"BadConnection\"}]}";
List<ExceptionStructure> list = JObject.Parse(s)
.SelectToken("Errors")
.ToObject<List<ExceptionStructure>>();

Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'

I am testing my Web API. Mocking the data I have this:
var objs = ((JArray)JsonConvert.DeserializeObject("{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}")).Values<JObject>();
Which gives me the error:
Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'
The thing is it was working. I must have changed something, but I don't know what.
My intent is to convert this JSON object to a list of .NET objects called Print which has the fields:
PrintId
Header
TX
CompnayRef
Just make a class and deserialize it.
public class Print
{
public int PrintId { get; set; }
public string Header { get; set; }
public string TC { get; set; }
public string CompanyRef { get; set; }
}
Print printObj = JsonConvert.DeserializeObject<Print>(yourJson);
printObj.PrintId = //...
As the message says, your object is JObject so don't cast it to JArray. Try this:
var objs = JsonConvert.DeserializeObject("{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}");
Update To get a collection List<Print>, your JSON needs to be an array. Try this (I made your JSON an array and added a second object):
string json = "[{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}"
+ ",{ \"PrintId\":20,\"Header\":\"header2\",\"TC\":\"tc2\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}]";
var objs = JsonConvert.DeserializeObject<List<Print>>(json);
//The loop is only for testing. Replace it with your code.
foreach(Print p in objs){
Console.WriteLine("PrintId: " + p.PrintId);
Console.WriteLine("Header: " + p.Header);
Console.WriteLine("TC: " + p.TC);
Console.WriteLine("CompanyRef: " + p.CompanyRef);
Console.WriteLine("==============================");
}
public class Print
{
public int PrintId { get; set; }
public string Header { get; set; }
public string TC { get; set; }
public string CompanyRef { get; set; }
}
Here is a fiddle.
Simply because { } is a jobject notation, to make it a jarray just put square brackets around it e.g. [{ }]. So in your case, just putting these two chars fixes the problem.
var objs = ((JArray)JsonConvert.DeserializeObject("[{ \"PrintId\":10,\"Header\":\"header\",\"TC\":\"tc\",\"CompanyRef\":\"00000000-0000-0000-0000-000000000000\"}]")).Values<JObject>();
you can try here
https://dotnetfiddle.net/RmgGw8
Note: You said it was working before. So this string input probably is a result of a serialization. You did not have a problem before, because your input was always an array with multiple items until this one. And your serializer is probably producing a single object (output starting with '{') instead of an array (output starting with '[') for single item arrays.
serializing List with single object as JSON object not JSON array
For me I was putting empty string as an object which caused the issue, I switched to "{}" which fixed my issue

Categories