Parsing Json into a dynamic c# object with a dynamic key - c#

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");

Related

Passing JSON as a string in the body of the POST request

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.

How to deserialize fields from incomplete JSON in .net? [duplicate]

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.

A simple parser from JSON string to Dictionary

I want to avoid importing a huge library to gain full JSON support.
My use case is REALLY simple: I need a parser to handle one specific case of JSON, where both key and value are strings, ie. { "name": "David" }. No nesting, no arrays, no object serialization.
The reason being, I use JSON only for i18n, and I have structure my translation files to be flat JSON.
Is it a good idea to hand roll my own parser?
Is there one out there already?
Are there easier solutions to my problem?
EDIT: yes, I do know JSON.net is the defacto solution for .NET, but it's not the solution for Unity (not natively). I really only need a tiny portion of its power.
System.Json might do the trick for you.
The JsonValue.Parse() Method parses JSON text and returns a JsonValue like
JsonValue value = JsonValue.Parse(#"{ ""name"": ""David"" }");
You can also have a look at The JavaScriptSerializer class is used internally by the asynchronous communication layer to serialize and deserialize the data that is passed between the browser and the Web server.
var Names = new JavaScriptSerializer().Deserialize<YourNameClass>(json);
OK I found one! https://github.com/zanders3/json
Has decent tests, minimal features and likely designed for my specific use case.
To load a JSON file:
Dictionary<string, object> locales = new Dictionary<string, object>();
TextAsset file = Resources.Load(name) as TextAsset;
var locale = file.text.FromJson<object>();
locales.Add(name, locale);
To use the JSON dictionary:
string activeLocale = "en-US";
var locale = locales[activeLocale] as Dictionary<string, object>;
var translation = locale[key] as string;
Dead simple.
Super simple Json parsing for Json strings like: { "name1": "David", "name2": "David" }. If you don't need to handle quoted commas and colons, eg {"weapons":"gun,mashine gun,supergun:2"} - change Regex.Split to simple String.Split.
private Dictionary<string, string> ParseJson(string content)
{
content = content.Trim(new[] { '{', '}' }).Replace('\'', '\"');
var trimmedChars = new[] { ' ','\"' };
//regex to split only unquoted separators
Regex regxComma = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
Regex regxColon = new Regex(":(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
return regxComma.Split(content)
.Select(v => regxColon.Split(v))
.ToDictionary(v => v.First().Trim(trimmedChars), v => v.Last().Trim(trimmedChars));
}

Way to quickly check if string is XML or JSON in C#

I'm using C# in a console app and I need a quick way to check if a string being returned from another service is XML or JSON.
I know if it was just XML, I could check it against a schema, or if it was just JSON I could try to parse it with JSON.Net, but is there a quicker way - maybe using build in .Net functions - just to tell which it is before then going on to process it?
Very simple:
Valid JSON starts always with '{' or '['
Valid XML starts always with '<'
I'm talking about non-space data.
public static bool IsJson(this string input){
input = input.Trim();
return input.StartsWith("{") && input.EndsWith("}")
|| input.StartsWith("[") && input.EndsWith("]");
}
it's a bit dirty but simple and quick
It is essentially enough to test the first character. Testing the last is a very rude way of testing well formedness. It doesn't guarantee it it simply heightens the chance that it is well formed.
If you wanted a more robust version you could take advantage of the short circuiting of if's to only evaluate well-formedness if the initial check is good. The below code relies on JSON.net
public static bool IsJson(this string input){
input = input.Trim();
Predicate IsWellFormed = () => {
try {
JToken.Parse(input);
} catch {
return false;
}
return true;
}
return (input.StartsWith("{") && input.EndsWith("}")
|| input.StartsWith("[") && input.EndsWith("]"))
&& IsWellFormed()
}
Thought I'd throw my solution in here too...
if (jsonData.Trim().Substring(0, 1).IndexOfAny(new[] {'[', '{'}) != 0)
throw new Exception("The source file must be in JSON format");
or an extension...
public static bool IsJson(this string jsonData)
{
return jsonData.Trim().Substring(0, 1).IndexOfAny(new[] { '[', '{' }) == 0;
}
usage:
if (!jsonData.IsJson())
throw new Exception("The source file must be in JSON format");
Check the HttpContentHeaders.ContentType property in of the returned HttpResponseMessage - HttpContentHeaders.ContentType Property. You'll see something like application/json; charset=utf-8, text/json; charset=utf-8, text/xml; charset=utf-8. It returns a MediaTypeHeaderValue instance you can examine. In your case, you would look at the MediaTypeHeaderValue.SubType Property This is what I use to make sure I parse and validate accordingly.
This is the safest and most accurate way. Unless of course you have an API that is returning xml or json as a string.
If you just had the Content-Type value as a string, you could use
MediaTypeHeaderValue.Parse(String) to help parse the Content-Type string.
The Content-Type property is defined as part the HTTP Spec and details are here: Content-Type [MDN]
The answers are nice, but I think you all forget the end of the JSON. Here is a good example that your methods wouldn't catch, and it will throw an exception when the parser tries to parse the JSON.
{
"positions":
[
{
"object": "position",
"powerState": "1",
"time": "72796",
"place": "1",
"clientId": ""
]
}
As you can see, it starts with { and ends with }, in the second hand starts with [ and ends with ], but someone forgot to close the 3rd {. This generates an error in the JSON parser.
I would say a more secure method is to check the beginning and the end for {[ that we find.
This doesn't happen often, but some people still handcraft their own JSON and forget some parts... Don't trust external data!
I hope it helps.

Invalid Json Primitives

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

Categories

Resources