This question already has answers here:
How can I deserialize an invalid json ? Truncated list of objects
(3 answers)
Closed 5 years ago.
I have incomplete JSON strings so the JSON is invalid, e.g.:
{
"Id": 0,
"Name": "John",
"Surname": "Smith",
"BadAnswers": ["Answer1", "Answer2"],
"CorrectAnswers": ["Answer3", "Answer4", "Answer5", "Answ
From this JSON I need to extract ID, Name and BadAnswers fields which are complete. I can't just deserialize this string using json.net because JSON is invalid.
Real case contains much more complex JSON with nested objects, lists, etc. but the idea the same.
So the main question is how to extract complete fields from partially completed and thus invalid JSON?
UPDATE 1. I can't make JSON valid by hand because it may be truncated at the random place not only at the place shown in the example. The only thing I know is that all required properties are present in truncated JSON. But if there any way to make JSON valid using json.net or any other library it would be a nice solution.
UPDATE 2. However there is already an answer to the question it is a quite low-level solution and requires a lot of manual work to manipulate with tokens and do not generalize well to different JSON formats.
The solution for you might be to use a JsonReader
For example, consider more complex JSON like this one:
{
"actions": [
{
"completed": true,
"id": 0
},
{
"completed": true,
"id": 1
}
],
"someProperty": false,
"anotherProperty": true,
"requiredIdProperty": 1,
"requiredArrayProperty": [
{
"nestedIdPropery": 0,
"nestedBoolProperty": true
},
{
"nestedIdPropery": 1,
"nestedBoolProperty": false
}
],
"truncatedObject": {
"firstProperty": 990,
"secondProperty": 0,
"thirdPrope
In this case, there are no problems with extracting requiredIdProperty using JsonReader but extracting requiredArrayProperty is painful because I need to manually handle all JSON tokens like JsonToken.ArrayStart and others. Said again, real case may and will contain much more complex JSON with more nested objects and arrays.
The ideal solution I'm looking for is to map JSON to a POCO class ignoring everything starting from the first invalid token or something like this.
The solution for you might be to use a JsonReader
using (FileStream s = File.Open("broken.json", FileMode.Open))
using (StreamReader sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
while (reader.Read())
{
// deserialize only when there's "{" character in the stream
if (reader.TokenType == JsonToken.StartObject)
{
//Your code
}
}
}
Is there a reason why you can't just add the two missing characters to the string and then deserialize?
I know this seems too obvious but just incase:
jsonString+="]}";
Then deserialize jsonString.
Related
I need a small help, because I don't know how to solve the below problem.
The requirement is simple, I have to sent the JSON to the server as a string parameter. The server basing on the key finds the mapping, and generically parses the JSON to some objects. That means, that the payload can have a different values and structures, each key has its own mapping - different data structure, number of parameters and so on. So the payload shouldn't be parsed outside the endpoint logic.
I know, that the Swagger sees the payload as a JSON, not as a string, and it tries to parse the data. How can I send the JSON as a string parameter to the endpooint without parsing the parameter? I have to parse it inside of the application, because of the mentioned mappings.
Example JSON:
{
"key": "test",
"payload": "[{"IDNew":1,"NameNew":"t1","DescriptionNew":"t1d", "IntegerValueNew":1, "DecimalValueNew":123.3}]"
}
When I'm trying to send the data in Swagger, I'm getting the below results:
curl -X POST "http://localhost:5110/api/InboundData" -H "accept: */*" -H "Content-Type: application/json-patch+json" -d "{ \"key\": \"test\", \"payload\": \"[{\"IDNew\":1,\"NameNew\":\"t1\",\"DescriptionNew\":\"t1d\", \"IntegerValueNew\":1, \"DecimalValueNew\":123.3}]\"}"
{
"errors": {
"payload": [
"After parsing a value an unexpected character was encountered: I. Path 'payload', line 3, position 17."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|d952c89f-4e25126d8cdf3697."
}
Data model:
[Required]
[JsonProperty(Required = Required.DisallowNull)]
[MaxLength(100)]
public string Key { get; set; }
[Required]
[JsonProperty(Required = Required.DisallowNull)]
public string Payload { get; set; }
The error clearly suggests that your JSON is not correct. If we analyze the payload property:
{
"key": "test",
"payload": "[{"IDNew":1,"NameNew":"t1","DescriptionNew":"t1d", "IntegerValueNew":1, "DecimalValueNew":123.3}]"
}
It seems you are creating a string object which further contains a JSON as a string. Generally, when you pass an array, you would pass it like this.
{
"key": "test",
"payload": [
{
"IDNew": 1,
"NameNew": "t1",
"DescriptionNew": "t1d",
"IntegerValueNew": 1,
"DecimalValueNew": 123.3
}
]
}
But, since value of the payload property is not properly escaped, which is why it is not properly able to parse it as it has unexpected characters for a string value.
If you strictly want to pass a JSON Array as a string object, you need to properly escape it in order to get it working. For example below is a JSON that contains JSON as a string with properly escaped properties:
{
"key": "test",
"payload": "[{\"IDNew\":1,\"NameNew\":\"t1\",\"DescriptionNew\":\"t1d\", \"IntegerValueNew\":1, \"DecimalValueNew\":123.3}]"
}
This is how you would escape your JSON if you strictly want to pass a JSON object that further contains JSON as string.
Or, perhaps, use single quote (') instead for the nested JSON. For example below is a JSON that contains JSON as a string with a single quotes for the properties:
{
"key": "test",
"payload": "[{'IDNew':1,'NameNew':'t1','DescriptionNew':'t1d', 'IntegerValueNew':1, 'DecimalValueNew':123.3}]"
}
UPDATE
I just wanted to add a suggestion that would be less confusing and would generate an accurate output for the scenario.
It would be nice if you generate the models for your intended JSON string and serialize the model to get a JSON string then do the assignment to payload property.
var payload = new List<payloadSample1>();
payload.Add(new payloadSample1{ IDNew = 1, NameNew = "t1", DescriptionNew = "t1d" });
var payloadStr = JsonConvert.SerializeObject(payload);
// payloadStr would contain your JSON as a string.
In C#, you can also generate dynamic type objects. Use those if your JSON is constantly varying and you find it hectic to create many models for many api requests.
var payload = new List<dynamic>();
payload.Add(new { IDNew = 1, NameNew = "t1", DescriptionNew = "t1d" });
var payloadStr = JsonConvert.SerializeObject(payload);
// And even then, if you have a further JSON object to send:
var payloadParent = new { key = "test", payload = payloadStr };
// send payloadParent as your json.
This is not the cleanest approach because of many reasons one out of those would be, when there is a change in your model, you will have to manually analyze all your dynamic objects and change all the references where you are using it. But, certainly, it will reduce the confusion behind escaping and maintaining the strings.
If you are using JavaScript make the api call, then generate a proper JSON object and then stringify it to get a string.
This question already has answers here:
Deserialize JSON with C#
(10 answers)
Closed 2 years ago.
I'm trying to extract specific data, in this case "Name" from a JSON file so that I can use it for the rest of my code later.
My current code where I load JSON:
public static void LoadJson()
{
using (StreamReader r = new StreamReader(#"C:\Users\Work\Documents\MyJson.json"))
{
string json = r.ReadToEnd();
var o = JsonConvert.DeserializeObject<JObject>(json);
var h = o.Value<JObject>("Data")
.Value<JArray>("Accounts");
Console.WriteLine(h[0]);
}
}
JSON example:
{
"Data": {
"Accounts": [
{
"Name": "owner",
"Address": "123456"
},
{
"Name": "Lerris",
"Address": "179672"
}
]
}
}
The output I get from my code right now:
JSON length is much longer than the one I posted above, but it was just to make an example.
Question:
How do I obtain and define both "Name" and "Address" value so that I can use them for the rest of my code?
I hope you guys will get what I mean. If I weren't specific enough please just say and I'll try to explain again.
See this section:
Use JsonDocument for access to data
I'm trying to parse this Google calendar response I'm getting from their Rest API using c#, but I seem to keep getting stuck. [edited] Update, the # symbol isn't preventing the drill down, I verified by replacing the # with _at_. See the screenshot of the Quick watch:
I'm sure I'm accessing this incorrectly...
Here's the jsonString I'm trying to parse:
{
"kind": "calendar#freeBusy",
"timeMin": "2015-06-12T14:00:00.000Z",
"timeMax": "2015-06-14T14:00:00.000Z",
"calendars": {
"joe#bobs.com": {
"busy": [
{
"start": "2015-06-13T18:30:00Z",
"end": "2015-06-13T19:30:00Z"
},
{
"start": "2015-06-13T20:30:00Z",
"end": "2015-06-13T21:30:00Z"
},
{
"start": "2015-06-13T23:00:00Z",
"end": "2015-06-14T00:00:00Z"
}
]
}
}
}
I've tried using:
dynamic myObj = Json.Decode(jsonString);
and
var myObj = JsonConvert.DeserializeObject(jsonString);
but I can't figure out how to get into the joe#bobs.com key (which is dynamic based on what I send up) to cycle through all the busy times.
Ideas?
You can access it via a string indexer:
var myObj = JsonConvert.DeserializeObject<dynamic>(jsonString);
Console.WriteLine(myObj.calendars["joe#bobs.com"]);
I have dealt with a similar problem in the past, however mine was a matter of hyphen, i simply replaced hyphen with underscore. you could potentially do something similar however seeing that it's a e-mail address, it might be a better to modify the schema (regular-expression seeing that you receive json from a third party API) create a new key "mail" so that you can ensure that you keep the original email address intact.
But perhaps more importantly, as you query this API perhaps you already knew the email, if so you could simply do a regex replace:
string json = '... {"joe#bobs.com":...}...';
Regex regex = new Regex(#"\b[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b");
string jsonfixed = regex.Replace(json, "email");
You can enter either of these URLs into a browser and verify that they return valid xml:
http://maps.googleapis.com/maps/api/geocode/xml?`address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false"
...or json:
http://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false%22
...but when attempting to get the xml programmatically using this code (after installing Json.NET via NuGet into my project and dropping a dataGridView on my Windows form):
dataGridView1.DataSource = GetLocationData("http://maps.googleapis.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false");
private JArray GetLocationData(string uri)
{
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
var webResponse = (HttpWebResponse)webRequest.GetResponse();
var reader = new StreamReader(webResponse.GetResponseStream());
string s = reader.ReadToEnd();
return JsonConvert.DeserializeObject<JArray>(s);
}
...I get:
Newtonsoft.Json.JsonReaderException was unhandled
_message=Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
I thought, okay, this actually is json code, not xml, so I replaced "xml" with "json" in the URL, expecting more joy in Mudville.
However, when attempting to get the same data as json, I also get an exception, namely, "System.InvalidCastException was unhandled _message=Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'."
Why, and how can I fix it? Is it possible to also grab the data as xml?
Using the json URL is correct. Your problem is that the JSON response is not giving you an array which is your error.
Notice that the response you get back is an object denoted by the {
{
"results" : [
{
"address_components" : [
{
"long_name" : "1600",
"short_name" : "1600",
"types" : [ "street_number" ]
},
....
If it was an array, you would get back [ instead. You should use JObject or a custom model instead of JArray. The results element is what contains the actual array that you will need to loop through.
Pseudo for the result you are actually getting in the response:
object
{
Result[] results;
string status;
}
You can also grab the XML version if you want, but then you need to actually have an object model defined to match and use the XmlSerializer to deserialize it or load it into an XmlDocument (lots of ways to work with XML). However, you cannot pass XML into the JSON serializer as it is expecting a JSON string.
EDIT:
There are methods on JsonConvert to convert from XML. See this answer here: How to convert JSON to XML or XML to JSON?
Could you help me for resolving this issue. I have one asp.net application, in this i am using Javascript serializer for serializing a dataset followed by convertion to the list. That code is shown below.
JavaScriptSerializer json = new JavaScriptSerializer();
strJson = json.Serialize(aclDoc);
But, at the time of deserializing i got one ArguementException like Invalid Json Primitives with my Json value. My json value is
[{"Id":"F79BA508-F208-4C37-9904-DBB1DEDE67DB","App_Id":"ScriptFlow","Name":"New form","FriendlyName":"","Read":"Revoke","ReadRule":"a353776f-cbdc-48b7-a15b-4a2316d19b05","Update":"Grant","UpdateRule":"be30c34e-33ec-4c0a-9f09-4fd483f5f1b9","Create":"Revoke","CreateRule":"898dce4d-4709-45b6-8942-d7efb07cbd86","Delete":"Revoke","DeleteRule":"aa14d435-dec8-4ade-ad9b-830ae5ee15d0"}][{"Id":"1","Doc_Id":"858E013C-5775-4FDF-AA1E-2C84053EE39F","Name":"TextBox1","FriendlyName":"TextBox1","Read":"Grant","ReadRule":"0a2e3c0e-ad8f-4f75-9160-cfd9827ac894","Update":"Grant","UpdateRule":"ecad3cf4-104f-44dc-b815-de039f3a0396"},{"Id":"2","Doc_Id":"858E013C-5775-4FDF-AA1E-2C84053EE39F","Name":"TextBox2","FriendlyName":"TextBox2","Read":"Grant","ReadRule":"81e0e9ef-09f7-4c25-a58e-d5fdfbd4c2ba","Update":"Grant","UpdateRule":"2047f662-c881-413b-a1f9-69f15bf667fc"}]
The code for deserializing is:
JavaScriptSerializer json = new JavaScriptSerializer();
lstDoc = json.Deserialize<List<ACLDocument>>(value);
return lstDoc;
where lstDoc is a List Collection of type of my class
I got the exception like this:
Invalid JSON primitive:
{"Id":"1","Doc_Id":"858E013C-5775-4FDF-AA1E-2C84053EE39F","Name":"TextBox1","FriendlyName":"TextBox1","Read":"Grant","ReadRule":"0a2e3c0e-ad8f-4f75-9160-cfd9827ac894","Update":"Grant","UpdateRule":"ecad3cf4-104f-44dc-b815-de039f3a0396"},{"Id":"2","Doc_Id":"858E013C-5775-4FDF-AA1E-2C84053EE39F","Name":"TextBox2","FriendlyName":"TextBox2","Read":"Grant","ReadRule":"81e0e9ef-09f7-4c25-a58e-d5fdfbd4c2ba","Update":"Grant","UpdateRule":"2047f662-c881-413b-a1f9-69f15bf667fc"}].
Please help me for resolving this issue. Thanks in advance
Your input string is really a wrong JSON string. You input consist from two correct JSON strings:
[
{
"Id": "F79BA508-F208-4C37-9904-DBB1DEDE67DB",
"App_Id": "ScriptFlow",
"Name": "New form",
"FriendlyName": "",
"Read": "Revoke",
"ReadRule": "a353776f-cbdc-48b7-a15b-4a2316d19b05",
"Update": "Grant",
"UpdateRule": "be30c34e-33ec-4c0a-9f09-4fd483f5f1b9",
"Create": "Revoke",
"CreateRule": "898dce4d-4709-45b6-8942-d7efb07cbd86",
"Delete": "Revoke",
"DeleteRule": "aa14d435-dec8-4ade-ad9b-830ae5ee15d0"
}
]
and
[
{
"Id": "1",
"Doc_Id": "858E013C-5775-4FDF-AA1E-2C84053EE39F",
"Name": "TextBox1",
"FriendlyName": "TextBox1",
"Read": "Grant",
"ReadRule": "0a2e3c0e-ad8f-4f75-9160-cfd9827ac894",
"Update": "Grant",
"UpdateRule": "ecad3cf4-104f-44dc-b815-de039f3a0396"
},
{
"Id": "2",
"Doc_Id": "858E013C-5775-4FDF-AA1E-2C84053EE39F",
"Name": "TextBox2",
"FriendlyName": "TextBox2",
"Read": "Grant",
"ReadRule": "81e0e9ef-09f7-4c25-a58e-d5fdfbd4c2ba",
"Update": "Grant",
"UpdateRule": "2047f662-c881-413b-a1f9-69f15bf667fc"
}
]
but you can not concatenate two JSON strings. To say exactly what you receive after such concatenating in not more a JSON string.
I recommend you to verify JSON strings in http://www.jsonlint.com/. Just cut and paste the data which you need to verify and click "Validate" button.
To answer the question directly, since everyone thinks this is a Microsoft forum and not answering directly.
The string is sent as a 2 element array. You forgot the '[' in the beginning of the string which denotes that the containing values are an array structure.
Insert the '[' in the beginning of the string and the error should go away.
This is a useful little tool for examining your JSON objects:
http://jsonviewer.codeplex.com/
See if you have any // or commented lines in project.json
Removing this has solved the same problem for me