I am consuming a web service that will calculate tax. The problem is I don't always get the data back in exactly the same formatn (see example below). When I deserialize the data my code throws an exception. Any tips on what I can do to allow the deserialization to handle a single element or an array of a single element? FYI, I get back a lot more data in addition to the tax, but I am only showing the tax part to keep it simple.
Sometimes I get the data like this:
{
"data": {
"tax": [{
"amount": 0.00,
"category": 0.0
}]
}
}
Sometimes I get it like this:
{
"data": {
"tax": {
"amount": 336.01,
"category": 0.0
}
}
}
Here is my class:
public class Tax
{
public float amount { get; set; }
public float category{ get; set; }
}
I am thinking about adding an [XmlIgnore] attribute and manually deserailizing to get the tax data, but I would like to stay away from that if possible.
Not sure how XmlIgnore would help with your JSON serialization, but i would suggest using Newtonsoft.Json to deserialize your payload to JObject. Then you can use Linq to JSON to investigate the result and perhaps manually instantiate your own object based on the type of "tax" property (JArray or JObject)
see LINQ to JSON for more info.
Make two (or more) different classes, then use the one that doesn't throw an exception when you deseralize.
It looks like you could deseralize the array data using this class:
public class data
{
public Dictionary<string, double> tax { get; set; }
}
If that class successfully deserializes, you can then copy it over to the tax class, either manually, or by using Reflection.
I'd use JSON.Net (link to nuget). Then I'd get a JObject from JObject.Parse method and check whether the relevant child element is JObject or JArray. Then, I'd convert it to your data class (or a dynamic type)
dynamic taxData;
var json = JObject.Parse(response);
var rawTaxData = json["data"]["tax"];
if (rawTaxData is JObject)
{
taxData = JsonConvert.DeserializeObject(rawTaxData);
}
else if (rawTaxData is JArray)
{
var actualData = rawTaxData [0];
taxData = JsonConvert.DeserializeObject(actualData);
}
Also, just to be sure that your server actually returned data and not, for example, error message, use TryGetValue:
JToken dataToken;
if (!json.TryGetValue("data", out dataToken))
{
var rawTaxData = dataToken["tax"];
// ...
}
Related
I am getting JSON data from a webservice. it is providing me with FORM DATA with different questions and answers. every answer is a different c# object. I am trying to find the best way to map the ANSWERS to correct c# object.
for example if Question Id is "37" Then its a Address Object.
I have JSON String like in this format below
"answers": {
"37": {
"name": "yourAddress37",
"order": "6",
"sublabels": "{\"cc_firstName\":\"First Name\",\"cc_lastName\":\"Last Name\",\"cc_number\":\"Credit Card Number\",\"cc_ccv\":\"Security Code\",\"cc_exp_month\":\"Expiration Month\",\"cc_exp_year\":\"Expiration Year\",\"addr_line1\":\"Street Address\",\"addr_line2\":\"Street Address Line 2\",\"city\":\"City\",\"state\":\"State \\/ Province\",\"postal\":\"Postal \\/ Zip Code\",\"country\":\"Country\"}",
"text": "Your Home Address:",
"type": "control_address",
"answer": {
"addr_line1": "148 east 38st ",
"addr_line2": "",
"city": "Brooklyn ",
"state": "Ny",
"postal": "11203",
"country": ""
},
"prettyFormat": "Street Address: 148 east 38st <br>City: Brooklyn <br>State / Province: Ny<br>Postal / Zip Code: 11203<br>"
},
"38": {
"name": "emergencyContact",
"order": "9",
"sublabels": "{\"prefix\":\"Prefix\",\"first\":\"First Name\",\"middle\":\"Middle Name\",\"last\":\"Last Name\",\"suffix\":\"Suffix\"}",
"text": "Emergency Contact Name:",
"type": "control_fullname",
"answer": {
"first": "Pauline ",
"last": "Sandy "
},
"prettyFormat": "Pauline Sandy "
}
}
and it MAPS to following c# property
public Dictionary<int, answer> answers{ get; set; }
Then I have a generic Answer class
public class answer
{
public string name { get; set; }
public dynamic answer { get; set; }
}
if you look at the ANSWER data from json then you will see its different for every question. for example one answer would be ADDRESS OBJECT, other answer would be FIRST & LAST NAME object.
my question is, how can i deserialize json into correct objects/properties automatically? I can create different POCO objects, such as address & ProfileName, but how would i map them automatically to correct object/property.
EDIT:
Loop through all Answers
foreach (var a in item.answers)
{
// pass the ANSWER OBJECT (dynamic data type) to function
createNewApplication(System.Convert.ToInt16(a.Key), a.Value.answer,ref app);
}
private void createNewApplication(int key, dynamic value,ref HcsApplicant app)
{
if (key == 4) // data is plain string
app.yourPhone = value;
if (key == 8)
app.yourEmail = value;
if (key==37) // data is a object
app.address = value.ToObject<address>();
}
is this approach OK? any cleaner way of doing it?
I personally don't like every option that involves custom parsing and looking directly on the questions.
You can make use of partial deserialization via JToken class.
Just declare your answers dictionary as such:
public Dictionary<int, JToken> Answers{ get; set; }
And then whenever you need the address page you can simply do Answers[37].ToObject<Address>(). How you manage to call this method, depends upon the rest of your code, but you can embed it in properties, in a big switch, in multiple methods, one for each class. One option I like is to have a static From method in each deserializable class:
public class Address
{
public string Name { get; set; }
// all the othe properties
// ....
public static Address From(Dictionary<int, JToken> answers)
{
return answers?.TryGetValue(37, out var address) ?? false
? address?.ToObject<Address>()
: null;
}
}
// so you can just write:
var address = Address.From(answers);
As a side note, remember that the default deserialization settings for Json.Net are case insensitive, so you can deserialize the name property from JSON to a more idiomatic Name property on your POCOs.
Make a constructor for each answer type that constructs by parsing a JSON object string. Make all the answers implement an interface, e.g. IAnswer. Map all constructors (as functions) to the corresponding question IDs in a dictionary. Lastly, loop through the questions, call each constructor, and maybe put them in a new dictionary.
Example code:
interface IAnswer { };
public class ExampleAnswer : IAnswer
{
public ExampleAnswer(String JSONObject)
{
// Parse JSON here
}
}
delegate IAnswer AnswerConstructor(String JSONObject);
Dictionary<int, AnswerConstructor> Constructors = new Dictionary<int, AnswerConstructor>()
{
{1234, ((AnswerConstructor)(json => new ExampleAnswer(json)))}
// Add all answer types here
};
Dictionary<int, IAnswer> ParseAnswers(Dictionary<int, String> JSONObjects)
{
var result = new Dictionary<int, IAnswer>();
foreach (var pair in JSONObjects)
result.Add(pair.Key, Constructors[pair.Key](pair.Value));
return result;
}
Edit: Look at Matt's answer for some good options for how to parse JSON.
Edit2, In response to your edit: That looks like a good way of doing it! I think it's better than my answer, since you can keep all type information, unlike my method.
The only thing I see that you might want to change is using else if or switch instead of multiple ifs. This could increase performance if you have many answers.
You have a couple of options:
Deserialize into a dynamic object using the System.Web package as per this answer or the JSON.Net package as per this answer then use conditional checks/the null propagation operator to access a property.
Automatically deserialize down to the level where there are differences, then have code to manual deserialize the properties that are different into the correct POCO types on your parent Deserialized object.
Leverage one of the Serialization Callbacks provided by JSON.Net (OnDeserializing or OnDeserialized) to handle populating the different properties into the correct types as part of the deserialization pipeline.
With approaches 2 and 3 you could write a nicer helper method on your POCO that inspected the objects properties and returned a result which would be the type that was set (I would recommend returning an Enum) e.g.:
public PropertyTypeEnum GetPropertyType(MyPocoClass myPocoClass)
{
if (myPocoClass.PropertyOne != null)
{
return PropertyTypeEnum.TypeOne;
}
else if (...)
{
return PropertyTypeEnum.TypeN
}
else
{
// probably throw a NotImplementedException here depending on your requirements
}
}
Then in your code to use the object you can use the returned Enum to switch on the logical paths of your code.
I am dynamically taking different JSON structures into various C# structures, using RestSharp and IRestResponse<T> response = client.Execute<T>(request). But, one particular JSON result is giving me trouble, where it starts and ends with brackets...
My JSON starts and ends with "[" and "]" characters:
[
{
"first": "Adam",
"last": "Buzzo"
},
{
"first": "Jeffrey",
"last": "Mosier"
}
]
I've created this class structure:
public class Person
{
public string first { get; set; }
public string last { get; set; }
}
public class Persons
{
public List<Person> person { get; set; }
}
I use RestSharp within a method to deserialize dynamically into my Persons type T...
IRestResponse<T> response = client.Execute<T>(request);
return response;
The problem is that when T is Persons I get this error on the client.Execute line:
Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'.
I also tried with Json.Net and got this error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Persons' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.
Given the initial "[" character, I tried deserializing into a List of Persons. That stopped the error message and I had the right number of "Person" records BUT they were all null. (I confirmed casing of names was identical.) I also don't really want to use a List collection when there is always only one element to the array from the target server and so binding to "Persons" makes more sense than "List".
What is the correct way to deserialize this JSON into Persons and still within the scope of my dynamic IRestResponse<T> response = client.Execute<T>(request) methodology?
As mentioned in the comments, your json holds an array of persons. Therefore the target structure to deserialize to should match that.
Either use:
var response = client.Execute<List<Person>>(request);
or if you prefer the Persons class, change it to
public class Persons : List<Person>
{
}
I've readed others posts here about this question
Serializing a list of Object using Json.NET
Serializing a list to JSON
Merge two objects during serialization using json.net?
All very useful. Certain, I can serialize in one json two lists, but I cant deserialize it.
I´m working with Json Newtonsoft, C#, MVC5, framework 4.5. This is the scenario:
C# CODE
public class User
{
public int id { get; set; }
public string name { get; set; }
}
public class Request
{
public int id { get; set; }
public int idUSer{ get; set; }
}
List<User> UserList = new List<User>();
List<Request> RequestList = new List<Request>();
string json= JsonConvert.SerializeObject(new { UserList, RequestList });
JSON RESULT
{
"UserList":[
{
"id":1,
"name":"User 1"
},
{
"id":2,
"name":"User 2"
},
{
"id":3,
"name":"User 3"
}
],
"RequestList":[
{
"id":1,
"idUSer":1
},
{
"id":2,
"idUSer":1
},
{
"id":3,
"idUSer":1
},
{
"id":4,
"idUSer":2
}
]
}
C# DESERIALIZE
I dont Know how configure the settings of Json.Deserialize< ?, Settings>(json) for indicate what types of objects are being deserialized.
Change of approach
So that, change of approach, I've created a new class "Cover" in order to put the lists together and serialize one object
public class Cover
{
private List<User> user = new List<User>();
private List<Request> request = new List<Request>();
public List<User> User
{
get { return user;}
set { User = value;}
}
public List<Request> Request
{
get {return request;}
set {Request = value;}
}
}
SERIALIZE
string json = JsonConvert.SerializeObject(cover);
JSON The json result is the same.
DESERIALIZE
Cover result = JsonConvert.DeserializeObject<Cover>(json, new
JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
It's work fine. My situation is resolved but I have doubts about concepts, in my mind something is not clear:
MY QUESTIONS ARE:
For the first aproach:
Do you think that there is a way to deserialize a json with different lists of objects? Is not a good practice?
Second aproach: Why jsons are equals for first situation?
In JSON.NET you need to specify the type you're about to deserialize, by supplying its name as a type argument to DeserializeObject.
However, in this line:
string json= JsonConvert.SerializeObject(new { UserList, RequestList });
you create anonymous object and then serialize it - new { UserList, RequestList }. So there is the catch - you cannot use anonymous type as type arguments.
To handle such situations, JSON.NET provides DeserializeAnonymousType<>. It doesn't require you to supply the type argument; actually you can't as you going to deserialize anonymous type. Instead it is inferred from the type of the second argument, passed to the method. So you just create a dummy, anonymous object, without data and pass it to this method.
// jsonData contains previously serialized List<User> and List<Request>
void DeserializeUserAndRequest(string jsonData)
{
var deserializedLists = new {
UserList = new List<User>(),
RequestList = new List<Request>()
};
deserializedLists = JsonConvert.DeserializeAnonymousType(jsonData, deserializedLists);
// Do your stuff here by accessing
// deserializedLists.UserList and deserializedLists.RequestLists
}
Of course this all works fine, but this approach suggests that you already know the structure of the serialized data. If this structure doesn't match the structure of the initialized by you anonymous type you'll get nothing after the DeserializeAnonymousType method. And this is valid not just for the type of the properties of the anonymous type, but for their names too.
To your first question:
I would consider the option with the Cover class the 'best practice' as you are using the same model for serialization and deserialization and it's all up to Json.NET to figure out how to do the (de)serialization magic.
If for some reason you don't want to use this approach, there are two other options:
Anonymous types: http://www.newtonsoft.com/json/help/html/DeserializeAnonymousType.htm
Deserializing into a dictionary: http://www.newtonsoft.com/json/help/html/DeserializeDictionary.htm
To your second question - Are you sure the generated JSON is absolutely the same with both approaches? (You can use a tool like www.diffchecker .com to verify)
With your second approach the top-level names should be different - it should be 'Users' instead of 'UserList' and 'Requests' instead of 'RequestList'
I have to extract a part of json-string using .net or newtonsoft json.
JSON:
var json = "{\"method\":\"subtract\",\"parameters\":{\"minuend\":\"SOME_CUSTOM_JSON_OBJECT_DIFFERENT_FOR_EACH_METHOD\",\"subtrahend\":23}}";
C# Class:
class MyJson{
public string method { get; set; }
//public string parameters {get; set;}
public object parameters {get; set;}
}
I do not need to parse all the children of "parameters" json-object. "parameters" could be a very big object ([{obj1}...{obj1000}], objX of 1000 fields), parse which would be not performant.
I would like i.e. to pass it exactly as it is on some point, so conversion "string-C#object-string" would be redundant.
I do not want use Regexp or string transformations (string.Substring, Split and co), because of error margin, I know that all .net and newtonsoft string transformations based.
Question 1: if I define a property of type "object", how newtonsoft will handle this? (Documentation is worse than msdn, so I'm looking for the input from you, who already tried this).
static void Main(string[] args)
{
var json = "{\"method\":\"subtract\",\"parameters\":{\"minuend\":42,\"subtrahend\":23}}";
var data = JsonConvert.DeserializeObject<MyJson>(j);
// what internal representaion of data.parameters?
// How is it actually converted from json-string to an C# object (JObject/JsonObject).
}
In perfect case:
"parameters" is a string and calling
ExtractMyJson(jsonString)
gives me the json string of parameters.
Basically I need the newtonsoft version of
string ExtractMyJson(jsonString){
var p1 = jsonString.Split(",");
// .. varios string transformations
return pParams;
}
Note: please don't reference "dynamic" keyword or ask why no string transformations, it's the very specific question.
If you know that your parameters are unique you can do something like this:
class MyJson
{
public string method { get; set; }
public Dictionary<string,object> parameters { get; set; }
}
................
string json = "{\"method\":\"subtract\",\"parameters\":{\"minuend\":{\"img\": 3, \"real\": 4},\"subtrahend\":23}}";
var data = JsonConvert.DeserializeObject<MyJson>(json);
If you let it as object is going to receive the type Newtonsoft.Json.Linq.JObject.
Have you tried JTOKEN?
It is a rather simple solution to partially read basic or nested JSONs as described in this post.
For a nested JSON
{
"key1": {
"key11": "value11",
"key12": "value12"
}
"key2": "value2"
}
it would look like this
JToken token = JToken.Parse(json);
var value12 = token.SelectToken("key1.key12");
to get the element of the key "key12.
I think this could go nicely with your problem.
Well Objects are treated the same way your parent object is treated. It will start from the base of the graph. So if you have something like:
Person
{
Address Address {get;set;}
}
The Json will start Deserializing Address and then add in the Person object.
If you want to limit thesize of the graph depth you can use a setting like :
JsonConvert.DeserializeObject<List<IList<IList<string>>>>(json, new JsonSerializerSettings
{
MaxDepth = 2
});
For more configurations of the JsonSerializer check JsonSerializerSettings
If your field is an object then that object will have the KeyValuePair of every property that it holds, based on that when you cast that field you can access that type.(the behaviour is the same as assigning a type to an object in C#).
Update: So if you question using JsonObject or type, well JObject is and intermediary way to construct the json format in a generic format. But using the Type deserializatin means you can ignore properties you are not interested in. Mapping to a json with a type makes more sense because it creates a new object and dismisses the old JObject.
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);