So I've got a JSON string that I'm handling with json.net. I'm putting this into a dynamic object and then just accessing the values from that.
dynamic data = JObject.Parse(JsonString);
if(data !=null)
{
string names = data.names.all
int count = data.member_count;
}
The issue is if data doesn't contain member_count (or names.all) it doesn't throw an error it just stops dead (I assume it returns out). I've tried to search for a solution but I'm not even sure how to word it.
Related
In a C# Controller.cs how do I get a "child" or "nested" object from a "parent" object. I am currently able to retrieve the values for objects that are NOT nested, but I also need to be able to grab the values to certain child objects as well.
Please see my currently working code below that actually retrieves the data when the object is NOT nested. I am able to get the values invoiceNumber, email, and paymentMethod .
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
var obj = JObject.Parse(result);
string invoiceNumber = (string)obj["invoiceNumber"];
string email = (string)obj["email"];
string paymentMethod = (string)obj["paymentMethod"];
}
Now when I attempt to get the data for objects that are nested, I just get retuned NULL. These values are NOT actually null as when I am debugging in visual studio JSON Visualizer, they have values but I just do not know how to write the syntax I need in order to grab these that are "child" or "nested" objects. So as you can see in the code below I tried to call this value for amountSaved in every way that I could think of, but it just returns NULL each time.
string rate = (string)obj["discounts.[0].amountSaved"];
string rate2 = (string)obj["discounts.amountSaved"];
string rate3 = (string)obj["discounts amountSaved"];
string rate4 = (string)obj["discounts:amountSaved"];
string rate5 = (string)obj["{discounts}:amountSaved"];
string rate6 = (string)obj["{discounts}.amountSaved"];
string rate7 = (string)obj["discounts.{amountSaved}"];
string rate8 = (string)obj["{discounts.amountSaved}"];
I figured the solution might be something like I call the parent object first which in this case is called discounts and then after a period or colon or space(. :) or something, I enter the name of the child object which in this case is amountSaved. That did not work.
Please see my screenshot below. This is when I debugging in visual studio and use the JSON Visualizer. You can see what I mean by discounts being a parent object with child values such as amountSaved. You can also see that it has a value of 0.75. You can can also see what I mean by the other values that are not nested which I am able to grab like shippingMethod.
How can I accomplish this?
Thank you.
when you use the square brakets you should not put . between them. And you can omit square brakets and use dot syntax only if you have deserialized object, not just parsed it
string rate = (string)obj["discounts"][0]["amountSaved"];
I created a Yaml with filenames, so I can make my program check if every file of the list exists. I haven"t done much with yaml yet, and the documentations don't really help me.
This is my Yaml (It's pretty small):
DLLs:
- Filename1
- Filename2
- Filename3
At the moment, this is my code:
using (var reader = new StringReader(File.ReadAllText("./Libraries/DLLList.yml")))
{
/*
* List<string> allDllsList = deserialized yaml.getting all values of the "DLLs"-list
*/
var deserializer = new Deserializer();
var dlls = deserializer.Deserialize<dynamic>(reader)["DLLs"] as List<Object>;
/*This gives me the Error "Object System.Collections.Generic.Dictionary`2[System.Object,System.Object] cannot be converted into "System.String""*/
List<string> allDllsList = dlls.Cast<String>().ToList();
}
Can someone explain to me how I can get the values out of the Yaml file, and why it works in the way you do it?
Edit: Now it works, I used the wrong yaml, I had 2 versions
First, take the return value from deserializer.Deserialize<dynamic>(reader) and inspect it in the debugger. It's a Dictionary<String, Object>, and it's got an entry named "DLLs" that contains a List<Object>. The objects in that list are all strings. There you go:
var dlls = deserializer.Deserialize<dynamic>(reader)["DLLs"] as List<Object>;
// Use .Cast<String>() as shown if you want to throw an exception when there's something
// that does not belong there. If you're serious about validation though, that's a bit
// rough and ready.
// Use .OfType<String>() instead if you want to be permissive about additional stuff
// under that key.
List<string> allDllsList = dlls.Cast<String>().ToList();
Im trying to convert my List code lines to Dictionary since as i understand they are faster, and more easy to manage, like i can get its value with its key value rather than just index.
Thus, im trying to modify my json-deserializing code (which actually,Newtonsoft's), but i have no idea how can i convert raw json to dictionary with my own format.
Dictionary <string,Tag>
Tag class is my own class with member variables, contains tag informations.
it doesnt includes functions for sure.
String should be Tag.Name, a string member variable.
//TODO: Fix "Hacky" solution to deserialized lines into Dictionary
//Which means : Raw Json -> Deserialized data -> List -> Dictionary is very hacky in my perspective
//Should be : Raw Json -> Deserialized data -> Dictionary, but i have no idea to convert directly like that
else if (filename.Contains(".json")) // very janky method to detect json file. dont depend on file extension - rather depend on actual file format.
{
string line = String.Join("", Lines);
List<Tag> lv_list = new List<Tag>();
Dictionary<string,Tag> lv_dict = new Dictionary<string, Tag>();
lv_list = JsonConvert.DeserializeObject<List<Tag>>(line);
gVar.Tags.AddRange(lv_list);
gVar.gTagCount += lv_list.Count();
for (int i = 0; i < lv_list.Count(); ++i)
{
gVar.Tags2.Add(lv_list[i].Name, lv_list[i]);
}
int lv_tagcount = 1;
for (int i = 0; i < gVar.gTagCount; ++i)
{
gVar.Tags[i].TagCount = lv_tagcount;
++lv_tagcount;
}
I wouldn't bother deserializing directly to a Dictionary: if the JSON is formatted like an array, go ahead and deserialize it to a List first. There's nothing "hacky" about the two-step process.
Use LINQ's ToDictionary() method to get a dictionary from a list:
Dictionary<string,Tag> lv_dict = JsonConvert.DeserializeObject<List<Tag>>(line)
.ToDictionary(tag => tag.Name);
You seem to have a habit of initializing a variable with an empty collection that never gets used, and then setting the variable to some other value. This isn't helpful: just declare and set the variable at the same time. But based on this pattern I'm wondering if gVar is an object you're trying to initialize even though your code looks like it's trying to add things to that variable. Do you really want to do something more like this?
gVar.Tags2 = JsonConvert.DeserializeObject<List<Tag>>(line)
.ToDictionary(tag => tag.Name);
I'd also question whether the TagCount property is a good pattern. It looks like you're trying to make each Tag explicitly aware of its own position in the collection that it's found in. This is a code smell. Perhaps now that you're using a Dictionary that won't be necessary because you can look up the tag by its name in the Dictionary?
I'm attempting to deserialize a response from a REST API using JSON.NET.
dynamic resultObject = JsonConvert.DeserializeObject(responseText);
I'd like to not have to define classes for the different kinds of responses the REST API returns, as it changes often. I'd like to take advantage of dynamic runtime variables.
In VS2015, I've added watchers to see the values directly after the line of code above executes.
resultObject resolves to a null object, however, the watcher shows that the line code run directly results in aNewtonsoft.Json.Linq.JObject which is populated with the deserialized response string.
Why doesn't the dynamic var resultObject populate with the JObject?
var responseStream = e.Response?.GetResponseStream();
string responseText = "";
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
responseText = reader.ReadToEnd();
}
dynamic responseObject = JsonConvert.DeserializeObject(responseText);
foreach (var error in responseObject["errors"].Children())
{
errors.Add(error.Val);
}
}
UPDATE:
Contents of the JSON to parse:
JSON updated to remove debug information - problem persists.
https://jsonblob.com/57cb00c7e4b0dc55a4f2abe9
UPDATE 2:
It appears that JsonConvert.DeserializeObject() is parsing my JSON to have extra brackets around the entire object.
String as it is generated from the response stream:
"{\"message\":\"422 Unprocessable Entity\",\"errors\":[[\"The email must be a valid email address.\"],[\"The password must be at least 8 characters.\"]],\"status_code\":422}"
value of JsonConvert.DeserializeObject():
{{
"message": "422 Unprocessable Entity",
"errors": [
[
"The email must be a valid email address."
],
[
"The password must be at least 8 characters."
]
],
"status_code": 422
}}
UPDATE 3:
Converting to JObject.Parse resulted in the same output.
I changed the variable from type dynamic to JObject - to accept the response from JObject.Parse() and still the variable is set to null.
I think, JSonConvert is invalid for solve your task. You can simply use JObject and JObject.Parse and then iterate "errors" property by Item
Your problem is that, in the following line, you are assuming that "errors" is an array of JSON objects, each with a property named "Val":
foreach (var error in responseObject["errors"].Children())
{
errors.Add(error.Val);
}
However, "errors" is actually an array of arrays, and so error.Val evaluates to null. Instead you need to do something like:
var errors = new List<string>();
dynamic responseObject = JsonConvert.DeserializeObject(responseText);
foreach (dynamic errorList in responseObject["errors"].Children())
{
foreach (dynamic error in errorList.Children())
{
errors.Add((string)error);
}
}
Personally, however, I recommend avoiding use of dynamic because you lose the advantages of static, compile-time type checking. Code full of dynamic objects can also be hard to debug. Instead I would recommend the use of LINQ to JSON, specifically the SelectTokens() along with the JSONPath recursive descent operator ..* to pick out all string values inside the "errors" object like so:
var token = JToken.Parse(responseText);
var errors = token.SelectTokens("errors..*") // Iterate through all descendants of the "errors" property
.OfType<JValue>() // Filter those that are primitive values
.Select(v => (string)v) // Convert to their string values
.ToList(); // And evaluate the query as a list.
Example fiddle.
I'm writing a Web API ApiController with several PUT methods that receive JSON data. The JSON is not deterministic and hence cannot be hard-mapped to a custom C# object, but needs to be received as Dictionaries/Sequences (Maps/Lists).
I have tried using an IDictionary for the data parm of the PUT method in the controller, and this sort of works -- the data appears to be mapped from JSON to the dictionary. However, it's necessary to declare the dictionary as <String,Object>, and there's no clear way to then retrieve the Object values as their appropriate types. (I've found a few suggested kluges in my searching, but they are just that.)
There is also a System.Json.JsonObject type which I finally managed to get loaded via NuGet, but when I use that the system does not appear to know how to map the data.
How is this typically done? How do you implement an ApiController method that receives generic JSON?
I can see three basic approaches:
Somehow make Dictionary/Sequence work with Object or some such.
Make something like System.Json.JsonObject work, perhaps by swizzling the routing info.
Receive the JSON as a byte array and then parse explicitly using one of the C# JSON toolkits available.
(As to how dynamic the data is, JSON objects may have missing entries or extraneous entries, and in some cases a particular entry may be represented as either a single JSON value or a JSON array of values. (Where "value" is JSON array, object, string, number, Boolean, or null.) In general, except for the array/not array ambiguity, the relation between keys and value types is known.)
(But I should note that this is a large project and I'll be receiving JSON strings from several other components by other authors. Being able to examine the received type and assert that it's as expected would be quite useful, and may even be necessary from a security standpoint.)
(I should add that I'm a relative novice with C# -- have only been working with it for about 6 months.)
You've got to know what kind of data you're expecting, but I have had success doing this in the past using dynamic typing.
Something like this:
[Test]
public void JsonTester()
{
string json = "{ 'fruit':'banana', 'color':'yellow' }";
dynamic data = JsonConvert.DeserializeObject(json);
string fruit = data["fruit"];
string color = data["color"];
Assert.That(fruit == "banana");
Assert.That(color == "yellow");
}
Edit:
You either need to know the type you want to deserialize to beforehand - in which case you can deserialize it to that type immediately.
Or you can deserialize it to a dynamic type, and then convert it to your static type once you know what you want to do with it.
using Newtonsoft.Json;
using NUnit.Framework;
public class DTO
{
public string Field1;
public int Field2;
}
public class JsonDeserializationTests
{
[Test]
public void JsonCanBeDeserializedToDTO()
{
string json = "{ 'Field1':'some text', 'Field2':45 }";
var data = JsonConvert.DeserializeObject<DTO>(json);
Assert.That(data.Field1 == "some text");
Assert.That(data.Field2 == 45);
}
[Test]
public void JsonCanBeDeserializedToDynamic_AndConvertedToDTO()
{
string json = "{ 'Field1':'some text', 'Field2':45 }";
var dynamicData = JsonConvert.DeserializeObject<dynamic>(json);
var data = new DTO { Field1 = dynamicData["Field1"], Field2 = dynamicData["Field2"] };
Assert.That(data.Field1 == "some text");
Assert.That(data.Field2 == 45);
}
}