Deserializing Json with unexpected characters in property - c#

My application processes a Json that contains a list of objects. The properties of these objects are not completely known to me.
Example, in the following Json, only property "Id" is known to my application:
{"msgs": [
{
"Id": "Id1",
"A": "AAA"
},
{
"Id": "Id2",
"B": "BBB"
},
{
"Id": "Id3",
"C": "CCC"
}
]}
I want to parse these messages and extract the Id of each message. This has been working fine with the following code:
public class RootElem
{
[BsonElement("msgs")]
public List<JToken> Records { get; set; }
}
then read
var rootElem = JsonConvert.DeserializeObject<RootElem>(JSON_DATA);
Once I have my rootElem, I can iterate over each record in "Records" and extract the Id.
The problem is that sometime, some of the records will contain unexpected characters.
Example:
{
"Id": "Id2",
"B": "THIS CONTAINS UNEXPECTED DOUBLE QUOTE " WHAT SHOULD I DO?"
}
I tried adding error handling settings, but that didn't work:
var rootElem = JsonConvert.DeserializeObject<RootElem>(data, new JsonSerializerSettings
{
Error = HandleDeserializationError
});
private static void HandleDeserializationError(object sender, ErrorEventArgs errorArgs)
{
var currentError = errorArgs.ErrorContext.Error.Message;
Console.WriteLine(currentError);
errorArgs.ErrorContext.Handled = true;
}
I want to be able to access the rest of the records in the list, even if one/some of them contain these invalid chars. So I'm ok if "B" value of the 2nd record is return as null, or if the 2nd record is null altogether.
How can I achieve this?
p.s. I'm using Newtonsoft Json but I'm open to using other libraries.

The issue here is that what your application is receiving is not valid JSON, hence the errors you are seeing. The input should be properly escaped prior to being submitted to this method. If this is behind an HTTP API, the appropriate response would be a 400 as the request is not in a valid format. If you really need to work around this it's possible you could implement your own JsonConverter class and decorate the converting class with it, but this may not be possible as the JSON itself is invalid and the JsonReader is going to choke when it hits it.

Related

ASP.NET C# Unexpected JSON token when reading DataTable

I'm working in ASP.NET and I'm getting this error when trying to serialize a JSON string into a DataTable:
Unexpected JSON token when reading DataTable. Expected StartArray, got
StartObject
I've read other posts that have this same error and it seems like the error normally occurs when the JSON object is invalid. However, I've validated my JSON in JsonLint and it is fine. I'm not constructing the JSON, I'm receiving it from the Paysimple API. I'm also using very similar methods in other parts of my software and it's working fine, so I'm at a loss to explain why the error shows up here.
Any help is greatly appreciated. I don't have a lot of experience working with JSON.
Here is my code:
protected void LoadPaymentSchedule(int customerId)
{
// This method returns an object from Paysimple's API
RecurringPaymentResponse recurringPayment = StudioPaymentAccess.GetStudioPaymentSchedule(customerId);
// Convert the Json response to DataTable
string a = JsonConvert.SerializeObject(recurringPayment);
DataTable tblSchedules = JsonConvert.DeserializeObject<DataTable>(a);//**error occurs here
// Bind to gridview
if (tblSchedules.Rows.Count > 0)
{
grdPaymentSchedules.DataSource = tblSchedules;
grdPaymentSchedules.DataBind();
}
else
{
//No schedules found
}
}
And here is the JSON that is returned by the method above StudioPaymentAccess.GetStudioPaymentSchedule(customerId)
{
"CustomerId": 1149814,
"CustomerFirstName": "Evan W",
"CustomerLastName": "Studio4",
"CustomerCompany": null,
"NextScheduleDate": "2020-11-16T07:00:00Z",
"PauseUntilDate": null,
"FirstPaymentDone": false,
"DateOfLastPaymentMade": "2020-10-16T06:00:00Z",
"TotalAmountPaid": 10.0,
"NumberOfPaymentsMade": 1,
"EndDate": "2021-10-16T06:00:00Z",
"PaymentAmount": 10.0,
"PaymentSubType": "Moto",
"AccountId": 1184647,
"InvoiceNumber": null,
"OrderId": null,
"FirstPaymentAmount": 0.0,
"FirstPaymentDate": null,
"StartDate": "2020-10-16T06:00:00Z",
"ScheduleStatus": "Active",
"ExecutionFrequencyType": "SpecificDayofMonth",
"ExecutionFrequencyParameter": 16,
"Description": " ",
"Id": 181512,
"LastModified": "2020-10-16T07:30:43Z",
"CreatedOn": "2020-10-15T18:11:22Z" }
It looks like in order to deserialize a DataTable, the expected JSON should be an array.
A quick work around do that would be to adjust the serialization so that it writes out an array:
string a = JsonConvert.SerializeObject(new[] { recurringPayment });
Another option would be to bind directly to return model, assuming that DataTable isn't a requirement. For example, see the answer to Binding an ASP.NET GridView Control to a string array.
Are you trying to Deserialize RecurringPaymentResponse Object to System.Data.DataTable?
It will definitely fail if you trying to Deserialize RecurringPaymentResponse Object to System.Data.DataTable. As properties of two class are not same.
You should directly update gridview rows
GridViewRow row = (GridViewRow) GridView1.Rows[0]; //First row
row.Cells[0].Text = recurringPayment.CustomerId;
row.Cells[1].Text = recurringPayment.CustomerFirstName;
row.Cells[2].Text = recurringPayment.CustomerLastName;
//and so on.....
DataTable Expects array as...
{
"data":
[
{"ID":1,"Name":"Simon"},
{"ID":2,"Name":"Alex"}
]
}
I tryed to deserialize but don't ocurred the error to me, the deserialize run successful.
https://i.stack.imgur.com/4tcns.png

How do I parse the below dynamic JSON

I have a json which is badly formatted. I want to take out the status and order id from that json. Tried JSON parsing with object, but did not get the result. Please help,
My Json,
{
"formname": [
"Sale_Order_API",
{
"operation": [
"add",
{
"values": {
"Order_ID": "1250",
"Email": "xyz#yws.in",
"Order_Value": "100",
"Restaurant_Name": "HiTech",
"Order_Date": "13-Aug-2019",
},
"status": "Failure, Duplicate values found for
'Order ID'"
}
]
}
]
}
Please help.
This is my first question , please ignore mistakes.
I have tried something like this, But not able to get the inner values
dynamic resultdata = json_serializer.DeserializeObject(postData);
If I understand you correctly, you want to deserialize this JSON. On 'http://json2csharp.com/#' you can generate a C # class from your JSON. Or right by your own. There are plenty of tutorials on the Internet. In case your class, where you give the values of the Json, is called 'JSONResult', you could access the values as follows
var resultdata = JsonConvert.DeserializeObject<JSONResult>(postData);
JSONResult outPut = resultdata;
Console.WriteLine(outPut.formname[0]);
But the longer I look at the format of your JSON, the more confused I get. Where did you get the JSON from? From an API?

How to pull a specific value from dynamic JSON dictionary in C#

I'm trying to pull one specific piece of data from the json received from a geocoding request.
This is not a duplicate of the myriads of similar-sounding questions, because the json is dynamic and has extremely irregular arrays that change slightly between responses, so I can't create a model to parse to, neither can I navigate through it using key names.
This is the json of one response:
{
"Response":{
"MetaInfo":{
"Timestamp":"2019-07-28T13:23:04.898+0000"
},
"View":[
{
"_type":"SearchResultsViewType",
"ViewId":0,
"Result":[
{
"Relevance":1.0,
"MatchLevel":"houseNumber",
"MatchQuality":{
"City":1.0,
"Street":[
0.9
],
"HouseNumber":1.0
},
"MatchType":"pointAddress",
"Location":{
"LocationId":"NT_Opil2LPZVRLZjlWNLJQuWB_0ITN",
"LocationType":"point",
"DisplayPosition":{
"Latitude":41.88432,
"Longitude":-87.63877
},
"NavigationPosition":[
{
"Latitude":41.88449,
"Longitude":-87.63877
}
],
"MapView":{
"TopLeft":{
"Latitude":41.8854442,
"Longitude":-87.64028
},
"BottomRight":{
"Latitude":41.8831958,
"Longitude":-87.63726
}
},
"Address":{
"Label":"425 W Randolph St, Chicago, IL 60606, United States",
"Country":"USA",
"State":"IL",
"County":"Cook",
"City":"Chicago",
"District":"West Loop",
"Street":"W Randolph St",
"HouseNumber":"425",
"PostalCode":"60606",
"AdditionalData":[
{
"value":"United States",
"key":"CountryName"
},
{
"value":"Illinois",
"key":"StateName"
},
{
"value":"Cook",
"key":"CountyName"
},
{
"value":"N",
"key":"PostalCodeType"
}
]
}
}
}
]
}
]
}
}
I'm trying to get just the two coordinates inside NavigationPosition.
Before I start the tedious work of creating a method to manually pull out the data I need from the unparsed string, does anyone have a solution? Is there a way to iterate anonymously through the json arrays using a foreach or if statement?
If the response is dynamic then one option is to use dynamic deserialization
var dynamicObject = JsonConvert.DeserializeObject<dynamic>(jsonAsString);
You can iterate this object and write defensive code by checking null.
I am assuming that "NavigationPosition" will always lie under "location" and in turn under a list of "Result" under list of "View"
something like this.. (symbolic code)
if(dynamicObject.View != null && dynamicObject.View[0] != null && dynamicObject.View[0].Result[0] != null && dynamicObject.View[0].Result[0].Location != null )
{
var navigationPosition = dynamicObject.View[0].Result[0].Location.NavigationPosition;
// do something with it
}
It seems really cumbersome but if you have no control over json response, I think you should be able to get it right after some iterations :)

converting graph api for xml

I'm having trouble converting a string of json facebook graph api, I used the facebook C# and json.Net.
But at conversion time it returns this error: Name can not begin with the '0 'character, hexadecimal value 0x30.
This is the code:
dynamic result = await _fb.GetTaskAsync ("me / feed");
FBxml JsonConvert.DeserializeXNode string = (result.ToString ()). ToString ();
It looks like there is a problem with portion of the json string as mentioned below (taken from your link http://jsfiddle.net/btripoloni/PaLC2/)
"story_tags": {
"0": [{
"id": "100000866891334",
"name": "Bruno Tripoloni",
"offset": 0,
"length": 15,
"type": "user"}]
},
Json cannot create class that begins with a numeric value such as '0'. Try creating the classes using the link http://json2csharp.com/ you will get an idea.
To solve this problem you can create a dynamic object and go through each properties OR create a JsonConverter and write your code in the ReadJson to convert the "0" to a meaningful name. May be this can help you http://blog.maskalik.com/asp-net/json-net-implement-custom-serialization
If this is not your problem then update the question with more information like class structure of FBxml, call stack of the exception (from which line of the json code is throwing the exception), Json version etc.
As keyr says, the problem is with those JSON properties that have numeric names. In XML names can contain numeric characters but cannot begin with one: XML (see the Well-formedness and error-handling section).
My idea was to recursively parse the JSON with JSON.Net, replacing properties that had numeric names:
var jsonObject = JObject.Parse(json);
foreach (var obj in jsonObject)
{
Process(obj.Value);
}
XDocument document = JsonConvert.DeserializeXNode(jsonObject.ToString());
....
private static void Process(JToken jToken)
{
if (jToken.Type == JTokenType.Property)
{
JProperty property = jToken as JProperty;
int value;
if (int.TryParse(property.Name, out value))
{
JToken token = new JProperty("_" + property.Name, property.Value);
jToken.Replace(token);
}
}
if (jToken.HasValues)
{
//foreach won't work here as the call to jToken.Replace(token) above
//results in the collection modifed error.
for(int i = 0; i < jToken.Values().Count(); i++)
{
JToken obj = jToken.Values().ElementAt(i);
Process(obj);
}
}
}
This seemed to work well, prefixing numeric names with _. At this line:
XDocument document = JsonConvert.DeserializeXNode(jsonObject.ToString());
it crashed with an error saying that invalid/not well formed XML had been created. I don't have the actual error with me, but you can run the above code to replicate it.
I think from here you may need to revisit converting the JSON to XML in the first place. Is this a specific requirement?

c# dynamic json objects with dynamic names question

Before I get flagged for duplicate, I have the code from Dynamic json object with numerical keys working quite well now. The question with my numeric keys is that unfortunately, the JSON string I am getting is initially delimited by year, so would I use reflection to attempt to create a dynamic property on a dynamic object, and if so how? I know with a dynamic object I can't have obj["2010"] or obj[0]. In JavaScript this is no problem, just trying to get it working in C#. Ideas?
Example of JSON being returned:
{
"2010": [
{
"type": "vacation",
"alloc": "90.00"
},
Alternatively, sometimes the year is the second element as such:
I have no control over this json.
{
"year": [],
"2010": [
{
"type": "vacation",
"alloc": "0.00"
},
Maybe I'm misunderstanding your question, but here's how I'd do it:
static void Main(string[] args) {
var json = #"
{
'2010': [
{
'type': 'vacation',
'alloc': '90.00'
},
{
'type': 'something',
'alloc': '80.00'
}
]}";
var jss = new JavaScriptSerializer();
var obj = jss.Deserialize<dynamic>(json);
Console.WriteLine(obj["2010"][0]["type"]);
Console.Read();
}
Does this help?
I wrote a blog post on serializing/deserializing JSON with .NET: Quick JSON Serialization/Deserialization in C#
I have up-voted the question and JP's answer and am glad I dug around the internet to find this.
I have included a separate answer to simplify my use case for others to benefit from. The crux of it is:
dynamic myObj = JObject.Parse("<....json....>");
// The following sets give the same result
// Names (off the root)
string countryName = myObj.CountryName;
// Gives the same as
string countryName = myObj["CountryName"];
// Nested (Country capital cities off the root)
string capitalName = myObj.Capital.Name;
// Gives the same as
string capitalName = myObj["Capital"]["Name"];
// Gives the same as
string capitalName = myObj.Capital["Name"];
Now it all seems quite obvious but I just did not think of it.
Thanks again.

Categories