JavaScriptSerializer deserialize multiple JSON arrays in single string - c#

In short, I have a client Windows Forms app that receives a Json string from an API in the following form:
string textResult = "{"Data":[{"ID":"G0000013","M_CurBalanceOutstanding":52408.5}],"DataDetail":[{"ErrorDate":"\/Date(1410179960809+0200)\/","ErrorID":1,"ErrorInfo":"Success"}]}"
or formatted via http://www.jsoneditoronline.org/
{
"Data": [
{
"ID": "G0000013",
"M_CurBalanceOutstanding": 52408.5
}
],
"DataDetail": [
{
"ErrorDate": "/Date(1410164281557+0200)/",
"ErrorID": 1,
"ErrorInfo": "Success"
}
]
}
I am trying to de-serialize it like this:
var deserializer = new JavaScriptSerializer();
List<MatterDetailBalOutstanding> results = deserializer.Deserialize<List<MatterDetailBalOutstanding>>(textResult);
where textresult is my JSon string.
I have the following classes:
[DataContract]
class MatterDetailBalOutstanding
{
[DataMember]
public string ID { get; set; }
[DataMember]
public decimal M_CurBalanceOutstanding { get; set; }
[DataMember]
public List<MatterReturnStatusDetails> ErrorData;
public MatterDetailBalOutstanding(string _ID, decimal _M_CurBalanceOutstanding, List<MatterReturnStatusDetails> _ErrorData)
{
ID = _ID;
M_CurBalanceOutstanding = _M_CurBalanceOutstanding;
ErrorData = _ErrorData;
}
}
and:
[DataContract]
class MatterReturnStatusDetails
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Info { get; set; }
[DataMember]
public DateTime Date { get; set; }
public MatterReturnStatusDetails(int _ID, string _Info, DateTime _Date)
{
ID = _ID;
Info = _Info;
Date = _Date;
}
}
I just cannot get it to work? To my understanding it is possible to de-serialize a string containing two JSon arrays. I have read a ton of threads, and a lot of them suggest using another serializer. I have to go with JavaScriptSerializer though. Please could someone help with this? What am I doing wrong? Where am I missing something?
Update 1:
When I try:
MatterDetailBalOutstanding results = deserializer.Deserialize<MatterDetailBalOutstanding>(textResult);
I get the below error:
No parameterless constructor defined for type of 'ConsumeTestWCFApp.ConsumeTestWCFApp+MatterDetailBalOutstanding'.

You can use json2csharp to assist you in generating classes suitable for mapping your JSON. Here is the result :
public class Datum
{
public string ID { get; set; }
public double M_CurBalanceOutstanding { get; set; }
}
public class DataDetail
{
public DateTime ErrorDate { get; set; }
public int ErrorID { get; set; }
public string ErrorInfo { get; set; }
}
public class RootObject
{
public List<Datum> Data { get; set; }
public List<DataDetail> DataDetail { get; set; }
}
Then you can annotate and modify the generated classes further as necessary and use it in deserialization :
var result = deserializer.Deserialize<RootObject>(textResult);

This problem:
No parameterless constructor defined for type of
'ConsumeTestWCFApp.ConsumeTestWCFApp+MatterDetailBalOutstanding'.
occurs because your serialized classes do not have a default constructor. By creating a specific constructor like this:
class MatterDetailBalOutstanding
{
public MatterDetailBalOutstanding(string _ID, decimal _M_CurBalanceOutstanding, List<MatterReturnStatusDetails> _ErrorData)
{
...
}
}
you do not get a default constructor and have to add one yourself:
class MatterDetailBalOutstanding
{
public MatterDetailBalOutstanding(string _ID, decimal _M_CurBalanceOutstanding, List<MatterReturnStatusDetails> _ErrorData)
{
...
}
public MatterDetailBalOutstanding()
{
...
}
}
This may not be you biggest problem now, but I didn't see anyone answer that part of the question.

Related

JSON does not retain values after Deserialization

I want to deserialize a string which is actually an array of object, this is the output of the serialization
[
{
\"CallType\":1,\
"ExecutionStart\":\"2018-07-03T12:25:55.1919951+03:00\",\
"ExecutionEnd\":\"2018-07-03T12:25:55.3980081+03:00\",\
"UnitExecutionStart\":\"0001-01-01T00:00:00\",\
"OverallExecution\":205
}
]
This is the object to which I want do deserialize
[JsonObject]
public class PerformanceMetricsItemDtoX
{
public PerformanceMetricsItemDtoX()
{
}
public CallType CallType { get; } //=> CallType is an enum
public DateTime ExecutionStart { get; }
public DateTime ExecutionEnd { get; }
public DateTime UnitExecutionStart { get; }
public long OverallExecution { get; }
}
After deserializing
var result = value.SelectMany(item =>
JsonConvert.DeserializeObject<List<PerformanceMetricsItemDtoX>>(item));
The final object result has default values so it does not retain the value that is stored in the serialized version.
What am i doing wrong ?
Thanks
Btw I've tried using
var result = new System.Web.Script.Serialization.JavaScriptSerializer()
.Deserialize<List<PerformanceMetricsItemDtoX>>(value.FirstOrDefault());
but the output is the same.
Your PerformanceMetricsItemDtoX properties are readonly, so JsonConvert (and no one, actually) can't assign any value to them, after constructor is invoked. Use this:
[JsonObject]
public class PerformanceMetricsItemDtoX
{
public CallType CallType { get; set; } //=> CallType is an enum
public DateTime ExecutionStart { get; set; }
public DateTime ExecutionEnd { get; set; }
public DateTime UnitExecutionStart { get; set; }
public long OverallExecution { get; set; }
}

Converting JSON to Object fails - Cannot deserialize the current JSON object into System.Collections.Generic.List

I'm using the API of www.textlocal.in, which returns a JSON formatted object.
JSON
{
"warnings":[
{
"message":"Number is in DND",
"numbers":"917000000000"
}
],
"balance":900,
"batch_id":311110011,
"cost":1,
"num_messages":1,
"message":{
"num_parts":1,
"sender":"TXTLCL",
"content":"Test1"
},
"receipt_url":"",
"custom":"",
"inDND":[
"917000000000"
],
"messages":[
{
"id":"1350123781",
"recipient":918819437284
}
],
"status":"success"
}
My code with which I'm trying to parse the JSON:
private void button1_Click(object sender, EventArgs e)
{
var a = JsonConvert.DeserializeObject<List<jsonToObj[]>>(richTextBox1.Text);
}
public class jsonToObj
{
public warnings[] warnings { get; set; }
public int balance { get; set; }
public int batch_id { get; set; }
public int cost { get; set; }
public int num_messages { get; set; }
public message message { get; set; }
public string receipt_url { get; set; }
public string custom { get; set; }
public messages[] messages { get; set; }
public string status { get; set; }
}
public class warnings
{
public string message { get; set; }
public string numbers { get; set; }
}
public class messages
{
public string id { get; set; }
public int recipient { get; set; }
}
public class message
{
public int num_part { get; set; }
public string sender { get; set; }
public string content { get; set; }
}
I'm getting an exception with the following message:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the
current JSON object (e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[WindowsFormsApp1.Form2+jsonToObj[]]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object. Path 'warnings', line 1, position
12.'
First of all you have to figure out what your API returns.
Right now you're trying to parse a List of jsonToObj Arrays (List<jsonToObj[]>). You have to decide whether to use a jsonToObj[] or List<jsonToObj> or a simple jsonToObj which your API provides now:
var a = JsonConvert.DeserializeObject<jsonToObj>(richTextBox1.Text);
But this then throws:
JSON integer 918819437284 is too large or small for an Int32. Path 'messages[0].recipient', line 25, position 33."
So make sure you use a Long for that.
public class messages
{
public string id { get; set; }
public long recipient { get; set; }
}
Furthermore you can add inDND to your jsonToObj class if you need the info:
public class jsonToObj
{
...
public string[] inDND { get; set; }
...
}
Based on string you class structure should be like this :
public class Warning
{
public string message { get; set; }
public string numbers { get; set; }
}
public class Message
{
public int num_parts { get; set; }
public string sender { get; set; }
public string content { get; set; }
}
public class Message2
{
public string id { get; set; }
public long recipient { get; set; }
}
public class RootObject
{
public List<Warning> warnings { get; set; }
public int balance { get; set; }
public int batch_id { get; set; }
public int cost { get; set; }
public int num_messages { get; set; }
public Message message { get; set; }
public string receipt_url { get; set; }
public string custom { get; set; }
public List<string> inDND { get; set; }
public List<Message2> messages { get; set; }
public string status { get; set; }
}
It looks like your class structure is not proper, Make use of visual studio and generate C# class from json string and then using that generated class try to deserialize class.
Read : Visual Studio Generate Class From JSON or XML
I simulated your problem and made the following changes that worked:
Change the method that deserializes to this:
var a = JsonConvert.DeserializeObject<jsonToObj>(richTextBox1.Text);
The result of the JSON you receive is not a List, so it will not work to deserialize to List<>.
The recipient property of the messages class receives values larger than an integer, so it must be transformed into a long like this:
public long recipient { get; set; }
These changes solve your problem.
Looks like this is a very old post, still thought of answering.
First of all, your Json data is singular which means, either
var a = JsonConvert.DeserializeObject<List<jsonToObj[]>>(richTextBox1.Text);
or
var a = JsonConvert.DeserializeObject<List<jsonToObj>>(richTextBox1.Text);
may not work for you.
You can either try:
var a = JsonConvert.DeserializeObject<jsonToObj>(richTextBox1.Text);
or
enclose the data with [ and ], which would do the trick.
make sure your parsing single object vs list of objects.

JSon.NET deserialising subitems

For deserialisation I usually use an object with the same property names as found in the JSon and JsonConvert.DeserializeObject<Des>(jsonstring).
But now I came across this:
{
"id": 0815,
"name": "whatever"
"addedInfo": {
"thisisinteresting": 4711,
"id_str": "2336"
}
}
How can I tell JSon.Net to pull the 'thisisinteresting' part of the sub category into a class like:
class Des
{
int id;
string name;
int thisisinteresting;
}
The trivial way would be to actually model your class to the JSON structure:
public class AddedInfo
{
public int thisisinteresting { get; set; }
public string id_str { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
}
Then add a property to the RootObject to emit the property:
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
[JsonIgnore]
public int thisisinteresting { get { return addedInfo.thisisinteresting; } }
}
There are alternatives like creating a custom serializer or using JObject and deserialize the structure yourself, but I won't go into that. If you need to parse the JSON anyway, the price to deserialize it entirely is small.

Type 'SalesforceDataQueryComponent.Utils.SfdcObjects+SfdcCollection is not supported for deserialization of an array

JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
// Deserialize the response to get an array of CUSTOM Cases
var reportsList = jsSerializer.Deserialize<SfdcObjects.SfdcCollection<SfdcObjects.Assets>>(HttpUtility.UrlDecode(response));
throws an exception:
Error: System.InvalidOperationException: Type 'SalesforceDataQueryComponent.Utils.SfdcObjects+SfdcCollection`1[
[SalesforceDataQueryComponent.Utils.SfdcObjects+Assets, SalesforceDataQueryComponent, Version=1.2.0.0, Culture=neutral]]'
is not supported for deserialization of an array.
I can not figure it out the issue:
Objects:
namespace SalesforceDataQueryComponent.Utils
{
class SfdcObjects
{
// Used for Authentication
public class TokenResponse
{
public string id { get; set; }
public string issued_at { get; set; }
public string refresh_token { get; set; }
public string instance_url { get; set; }
public string signature { get; set; }
public string access_token { get; set; }
}
// All classes shown next are used to parse the HttpGet Response
public class SfdcCollection<T>
{
public bool Done { get; set; }
public int Size { get; set; }
public string NextRecordsUrl { get; set; }
public List<T> Records { get; set; }
}
public class SfdcAttributes
{
public string Type { get; set; }
public string Url { get; set; }
}
public class Accounts : Account
{
public SfdcAttributes Attributes { get; set; }
}
public class Assets : Asset
{
public SfdcAttributes Attributes { get; set; }
}
public class CustomAssets : Assets
{
public string StringInstallDate { get; set; }
}
public class Users : User
{
public SfdcAttributes Attributes { get; set; }
}
public class CustomCase : Case
{
public string StringCreatedDate { get; set; }
}
public class CustomCases : CustomCase
{
public SfdcAttributes Attributes { get; set; }
}
}
}
You do not include your response JSON in your question, however from the error message, your problem must be that the root JSON container in your response is an array. A JSON array, according to the JSON standard, looks like this:
[value1, value2, ..., valueN]
JSON serializers map types that implement ICollection or IEnumerable from and to JSON arrays.
Your root object SfdcCollection<T>, however, is NOT a collection or enumerable, despite its name. Instead it's a non-enumerable generic POCO:
public class SfdcCollection<T> // No IEnumerable<T>
{
public bool Done { get; set; }
public int Size { get; set; }
public string NextRecordsUrl { get; set; }
public List<T> Records { get; set; }
}
Thus a serializer will map this to a JSON object (which is a set of key/value pairs and looks like {"name1" : value1, "name2" : value2, ..., "nameN" : valueN }) instead of an array.
You need to update your data model to the JSON you are actually receiving. Try uploading your JSON to http://json2csharp.com/, it will automatically generate classes for you.
If you must use the classes in your question, you could ask another question about how to map the JSON you are actually receiving onto your required classes, using your desired serializer (e.g. Json.NET, DataContractJsonSerializer, JavaScriptSerializer, or etc.)

Flattening nested JSON object in JSON.NET

I have a simple JSON like this:
{
"id": 123,
"name": "BaseName",
"variation": { "name": "VariationName" }
}
Is there a simple way to map it with JSON.NET deserialization to:
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string VariationName { get; set; }
}
I can probably do it with a custom converter, but I hoped there would be a simpler way by annotating the class with attributes which would give instructions to deserialize the variation object just using the one property.
You could set up a class for variation and make VariationName a get-only property
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Variation variation { get; set; }
public string VariationName { get { return variation.VariationName; } }
}
class variation
{
public string name { get; set; }
}

Categories

Resources