JSON Parsing and Error in C# - c#

I am having trouble parsing a JSON from the Alpha Vantage API. The output of the JSON is as follows
{
"Realtime Currency Exchange Rate": {
"1. From_Currency Code": "BTC",
"2. From_Currency Name": "Bitcoin",
"3. To_Currency Code": "CNY",
"4. To_Currency Name": "Chinese Yuan",
"5. Exchange Rate": "43211.50782620",
"6. Last Refreshed": "2018-04-11 17:48:12",
"7. Time Zone": "UTC"
}
}
I am parsing it like this
using (var wc = new System.Net.WebClient())
json = wc.DownloadString(link);
dynamic stuff = JsonConvert.DeserializeObject(json);
string test = stuff["Realtime Currency Exchange Rate"]["5. Exchange Rate"];
However when I run the code, I am getting this error
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Cannot perform runtime binding on a null reference'
Anyone have any idea? If I print the value in a textbox, the value shows up but afterwards it shows that error. I am coding in c#
Thanks

Try creating an object to serialize to and use the JsonProperty attribute to map the json properties to the C# properties:
public class RealtimeCurrencyExchangeRate
{
[JsonProperty("1. From_Currency Code")]
public string CurrencyCode { get; set; }
}
Then use the correct type when deserializing.
var obj = JsonConvert.DeserializeObject<RealtimeCurrencyExchangeRate >(json);
References:
Spaces handling: Deserializing JSON when fieldnames contain spaces
DeserializeObject: https://www.newtonsoft.com/json/help/html/DeserializeObject.htm
Or, if you want to dynamically read the properties, you can create a custom contract resolver:
public class AlphaVantageApiContractResolver : DefaultContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
// derive the C#property name from the JSON property name
var cSharpPropertyName = propertyName;
// Remove all periods from the C#property name
cSharpPropertyName = cSharpPropertyName.Replace(".", "");
// replace all spaces with underscores
cSharpPropertyName = cSharpPropertyName .Replace(" ", "_");
// The value you return should map to the exact C# property name in your class so you need to create classes to map to.
return cSharpPropertyName;
}
}
and use this while deserializing:
var jsonSettings = new JsonSerializerSettings();
jsonSettings.ContractResolver = new AlphaVantageApiContractResolver();
var obj = JsonConvert.DeserializeObject<MyClass>(json, jsonSettings);
https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_DefaultContractResolver.htm#!
You will still have to create classes that map to the objects but now you don't have to worry about the JsonProperty attribute on every property. Just remember to remove periods and replace spaces with underscores in your C# property names. You will also have to write some code to remove numbers at the beginning of property names because this isn't allowed in C#.
If you can't pre-define your classes, you will need to deserialize anonymous objects and work with that.

Your issue more than likely stems from your JSON. Though your JSON is valid, you violate a couple of principals which may be affecting the binder.
You have spaces for your property name, which are often translated into underscores.
You have a period in your property name, this also may interfere with the dot notation.
You could do the approach recommended by Kyle to bind. If you would like to use dynamic, then you could fix the above, then do the following syntax.
dynamic json = JsonConvert.Deserialize<object>(...);
var value = json.realTimeCurrencyExchangeRate.fromCurrencyCode;
The C# binder doesn't like a period when you utilize dot notation and spaces, when they're translated with underscores. So you could use your space, but the translation may be different. You would need to look closer at your object.

Related

Convert string into a valid JSON in c#

In the code snippet below, the JSON string in the commented out jsonString variable is valid while the uncommented out one causes JObject.Parse to throw a JsonReaderException with the message:
After parsing a value an unexpected character was encountered: e. Path 'Key', line 1, position 15.
var jsonString = "{\"Key\":\"Value \"extra\" \"}";
//var jsonString = "{\"Key\":\"Value \\\"extra\\\" \"}";
JObject.Parse(jsonString);
Are there any methods available in Newtonsoft.Json or elsewhere that can transform a JSON string to make it valid?
No, because NewtonSoft cannot guess what you want. E.g. is extra a new key and did you just ommit a comma or is it part of the previous value, or is it just something that can be ignored. It would be better to have the thing you are consuming the json from construct valid json.
Using Regex might help you to resolve the existing JSON you have. If you can control how subsequent JSON is generated, you really should fix it at that point.
This solution counts the value as existing from the first " after a "key":, through to the last " before a , or a }, and then it reserializes the value to ensure that it is correctly escaped. If it finds ",, it expects it to be followed by another key ("key":). This is in an attempt to avoid red herrings (i.e. {"key": "test "," value"}) which might otherwise confuse it.
private static string FixJson(string json)
{
var regex = new Regex("\"(?<key>.*?)\"\\W?:\\W?\"(?<value>.*?)\"(?=,\".*?\"\\W?:|}$)");
return regex.Replace(json, new MatchEvaluator(m => {
var key = m.Groups["key"].Value;
var val = m.Groups["value"].Value;
return string.Format("\"{0}\":{1}", key, JsonConvert.SerializeObject(val));
}));
}
Disclaimer: It's a regular expression, it's not foolproof, and if your JSON is more broken than you have indicated, it will probably spit out broken JSON, or incorrect values, so use it at your own risk.
Try it online

Is "[]" valid JSON?

I'm having troubles de-serializing this JSON string using JSON.NET (note the quotes):
"[]"
Depending on which JSON validation website you go to, this is valid JSON (jsonlint for example says it is).
The JSON.NET code:
void Main()
{
string json = "\"[]\"";
var x = JsonConvert.DeserializeObject<User[]>(json);
Console.WriteLine(x);
}
// Define other methods and classes here
public class User
{
public string Id { get; set; }
public int Age { get; set; }
}
The exception
Error converting value "[]" to type 'UserQuery+User[]'. Path '', line 1, position 4.
Is there a way of forcing JSON.NET to parse this?
Part 1: Is "[]" valid JSON?
There are several documents and standards on JSON, and hundreds of parsers; and some of them suppose that JSON can only be object {} or an array [], but some allow single values like strings, numbers to be used as JSON.
Read this article, it widely describes this problem.
What is the minimum valid JSON?
This dispute on JSON validity is another question. In your case, it doesn't matter, because...
Part 2: why your code isn't working.
Even if we allow non-objects \ non-arrays to be valid JSON, then your JSON represents a single string equal to "[]". It could be anything else, not brackets, it is not an array notation, but just two symbols "[" and "]".
However, you try to parse this JSON as an array of objects, which will anyway result into error.
In other words, even if it is a valid JSON, then it is a valid JSON string, not JSON array.
var str1 = JSON.parse("\"[]\""),
str2 = JSON.parse("\"could be anything else, not brackets\""),
arr = JSON.parse("[]");
console.log(typeof str1);
console.log(typeof str2);
console.log(typeof arr);
var str1_s = JSON.stringify([]);
console.log("Valid JSON of an empty array: " + str1_s);
var arr_s = JSON.stringify("[]");
console.log("Partly valid JSON of a string '[]': " + arr_s);
Part 3: what should you do
The best idea - stop using invalid JSON as input. Tell whoever gave you this JSON that it is invalid JSON array and you cannot use it. You would be able to deserialize a JSON into your array of User if it was correct just like you use it:
string json = "[]";
var x = JsonConvert.DeserializeObject<User[]>(json);
Console.WriteLine(x);
If this JSON is provided from 3rd party services and you can do nothing about that, then you need to tidy it up and make it valid. Yeah, unfortunately, sometimes it happens.
How? It depends on what is your value when there ARE objects (users).
It may be a JSON-serialized JSON-string (double-serialized) like this, and then you need to deserialize a string, and then deserialize an array.
Or it can just have two odd quotes in the beginning and the end, and you can just remove them.
It is valid JSON, but the deserializer failes because the datatypes do not match.
"[]"
Is a string, so the deserializer wants to serialize it to a string.
[]
Is an empty array. So, in short, this should work:
string json = "[]";
var x = JsonConvert.DeserializeObject<User[]>(json);
Console.WriteLine(x);

C# preserve escape sequence when reading JSON content using Json.NET

C# preserve escape sequence when reading JSON content using Json.NET
Given the following json text content:
{ "Pattern": "[0-9]*\t[a-z]+" }
Which is reflected in a simple class:
public class Rule
{
public string Pattern { get; set; }
public bool Test(string text)
{
return new Regex(Pattern).IsMatch(text);
}
}
And it's deserialised like this:
var json = System.IO.File.ReadAllText("file.json");
var rule = JsonConvert.DeserializeObject<Rule>(text);
The value of Pattern is supposed to be a regex pattern. The problem is that, once the content is read, the "\t" escape sequence is immediately applied as a escape character which is a tab, resulting in the string value: [0-9]* [a-z]+.
What I understand is that the content is somewhat malformed, because it should look like this: [0-9]*\\t[a-z]+ to be valid within the Json content, escaping the backslash so it could be preserved and result into the actual pattern [0-9]*\t[a-z]+. But the file is user edited and I would just like to be able to loosely interpret the content, assuming that backslashes should be preserved (and escape sequences would not be transformed).
I tried to implement a custom JsonConverter but when looking up the token, the value is already resolved.
FIDDLE
I've tried the below code and it works...maybe i don't understand what is the problem or you can provide a sample that doesn't work with this:
StreamReader s= new StreamReader(#"test.txt");
string json = s.ReadToEnd();
json=json.Replace("\\","\\\\");
JObject obj = JObject.Parse(json);
string pattern = obj["Pattern"].ToString();
bool test = Regex.IsMatch("1 a", pattern);
test.txt contains just this:
{ "Pattern": "[0-9]*\t[a-z]+" }
Edit
As Thomasjaworsky remarks, instead of json=json.Replace("\\","\\\\"); is better to use Regex.Replace(json, #"(?<!\\)[\\](?!\\)", #"\\")
, it will do the same replace, but only if not already escaped. Two backspaces in row are untouched.

Properties Order while Deserialization using JSON.Net

I am trying to Deserialize the string to JSON Object using JsonConvert.DeserializeObject like below:
var str = "{ Value: \"File\",Text: \"OWENS & MINOR INFANT - 2228548\"}";
agreementnodes = JsonConvert.DeserializeObject<List<AgreementNode>>("[" + str + "]");
When the json is converted to an array the properties are alphabetically ordered. Example : Even though Value is first and Text is in the string the properties are displayed like below:
Even in the class declaration, I Value is Firs and Text is second. But when de-serializing, the properties are sorted alphabetically.
[JsonProperty(Order = 9)]
public string Value { get; set; }
[JsonProperty(Order = 10)]
public string Text { get; set; }
Is there any way to retain the order of the properties in the resultant array like I want resultantarray[0] = Value and resultantarray1 = Text?
Nothing wrong with json.net serializer. It's automatically ordered by alphabetical in quickwatch and watch windows. Check System.Web.HttpContext.SystemWebAssembly if you want. It's not a deserialized code.
The ordering of properties are undefined according to the specification. In spite of that the most current ECMAScript (JavaScript) specification requires an ordered format which also enables new cool applications like:
https://cyberphone.github.io/openkeystore/resources/docs/jcs.html#ECMAScript_Compatibility_Mode

how to validate JSON string before converting to XML in C#

I will receive an response in the form of JSON string.
We have an existing tool developed in C# which will take input in XML format.
Hence i am converting the JSON string obtained from server using Newtonsoft.JSON to XML string and passing to the tool.
Problem:
When converting JSON response to XML, I am getting an error
"Failed to process request. Reason: The ' ' character, hexadecimal
value 0x20, cannot be included in a name."
The above error indicates that the JSON Key contains a space [For Example: \"POI Items\":[{\"lat\":{\"value\":\"00\"}] which cannot be converted to XML element.
Is there any approach to identify spaces only JSON key's ["POI Items"] and remove the spaces in it?
Also suggest any alternative solution so that we needn't change the existing solution?
Regards,
Sudhir
You can use Json.Net and replace the names while loading the json..
JsonSerializer ser = new JsonSerializer();
var jObj = ser.Deserialize(new JReader(new StringReader(json))) as JObject;
var newJson = jObj.ToString(Newtonsoft.Json.Formatting.None);
.
public class JReader : Newtonsoft.Json.JsonTextReader
{
public JReader(TextReader r) : base(r)
{
}
public override bool Read()
{
bool b = base.Read();
if (base.CurrentState == State.Property && ((string)base.Value).Contains(' '))
{
base.SetToken(JsonToken.PropertyName,((string)base.Value).Replace(" ", "_"));
}
return b;
}
}
Input : {"POI Items":[{"lat":{"value":"00","ab cd":"de fg"}}]}
Output: {"POI_Items":[{"lat":{"value":"00","ab_cd":"de fg"}}]}
I recommend using some sort of Regex.Replace().
Search the input string for something like:
\"([a-zA-Z0-9]+) ([a-zA-Z0-9]+)\":
and then replace something like (mind the missing space):
\"(1)(2)\":
The 1st pair of parenthesis contain the first word in a variable name, the 2nd pair of parenthesis means the 2nd word. The : guarantees that this operation will be done in variable names only (not in string data). the JSON variable names are inside a pair of \"s.
Maybe it's not 100% correct but you can start searching by this.
For details check MSDN, and some Regex examples
http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.replace.aspx

Categories