Json to C# Deserialize - Property name is an int - how to fix? - c#

Okay so I'm trying to get data from an API, and it works. This is the data I get:
json data
Yet the only problem is, when I try to access the "7" and "10" property in order to get "rankPoints", I get a bug:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'The call is ambiguous between the following methods or properties: 'System.Console.WriteLine(string, params object[])' and 'System.Console.WriteLine(char[])''
This is the code that works:
var x = oMycustomclassname["rankedSeasons"];
This is the code that does not work:
var x = oMycustomclassname["rankedSeasons.7.10.rankPoints"];
I'm guessing it cant access the property because it is an int? But I cant change the data, since it is from an API.
Thank you,
MV

every sub item is another json object which can be accessed like a dictionary
var x = (int)oMycustomclassname["rankedSeasons"]["7"]["10"]["rankPoints"];

Related

Newtonsoft.Json.Linq.JObject 'does not contain a definition for X prop

I am trying to store the one property of my object in a variable and it gives me an error referring to my object does not have a definition for my property.
Error: 'Newtonsoft.Json.Linq.JObject' does not contain a definition for 'str'.
This only happens within my project, if I do it within a separate compiler, everything runs correctly and it should be, but I don't understand why I get this error in the project.
https://dotnetfiddle.net/Jf5xQf
The result you are receiving for JObject.Parse is of type JObject. To fetch the str value, you need to use
valorcito = d["str"];
You would be interested to read on querying Json with Linq with your current approach.

Receive nested anonymous objects in ASP.NET MVC controller

I need a ASP.NET MVC controller, which receives anonymous object from JS in JSON to iterate thru its properties. I used to do this, receiving Dictionary<string, object>. But now one of values is Array, and insted of
receivedDictionary[Photos] = [object, object, object]
it gets it as
receivedDictionary[Photos[0]] = object, receivedDictionary[Photos[1]] = object, receivedDictionary[Photos[2]] = object
I get not one dictionary entry with key = Photos and value = array, but many entries with key = Photos[x] and value = object.
How do I get it as one entry in dictionary or is there any better way to get it as dynamic anonymous object and iterate thru its properties just like in JS?
UPD: JSON looks like this:
{"fields":{"TotalFloors":"9","HouseNumber":"10","Photos":[{"id":0,"ParentID":0,"OriginalUrl":"py4s1y3uyqu","OriginalExt":".jpg","ThumbUrl":"2hn04w2lzuu","FormatUrls":{"WH_109_82_Url":"4cwjarqudvo","WH_766_454_Url":"oofm5qo21rr"}},{"id":0,"ParentID":0,"OriginalUrl":"t3csgq20iro","OriginalExt":".jpg","ThumbUrl":"j1uwwburmse","FormatUrls":{"WH_109_82_Url":"gm4qoery1u2","WH_766_454_Url":"a3c20re3g1d"}}],"Details":"Other details"}}
Controller definition:
[HttpPut]
public ActionResult restId(string className, int id, Dictionary<string, object> fields)
{
....
}
The JsonValueProvider used by the DefaultModelBinder seems to be treating array in an odd fashion in this case (based on the source here), so even a dynamic will most likely have the issue. (Don't think you'll have this issue in MVC 6 however)
However, calling the JavascriptSerializer directly (which funny enough is what the default provider uses) produces the results you're after:
var js = new JavaScriptSerializer();
var res = js.DeserializeObject(#"{'TotalFloors':'9','HouseNumber':'10','Photos':[...],'Details':'Other details'}");
To address your issue you could either alter the parameter to a string and run the above code in your action (obviously replacing the JSON string with the parameter), just means the JSON you're submitting from the front end would need to look more like:
// wrapping the JSON object in quotes to stringify it
{ 'fields' : "{ 'TotalFloors': '9', 'HouseNumber': .... }" }
Otherwise you could implement a custom JsonValueProvider like the one proposed here: https://json.codeplex.com/discussions/347099
The custom value provider is probably the cleaner solution.

Deserialized JSON object to dynamic type but getting RuntimeBinderException accessing properties?

I am using JSON.net in a C# Windows Form application to deserialize a JSON string to a dynamic object:
dynamic jsonObj = JsonConvert.DeserializeObject(strJson);
I'm using the following test JSON for testing:
{"payload":"thePayload","number":3,"dialogResult":"one"}
When I run the code, I can indeed access the properties of the dynamic object using an associative array approach:
var x = jsonObj["payload"];
However, if I try to access the content using property names:
var x = jsonObj.payload;
It works but I get the following Exception:
A first chance exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in Microsoft.CSharp.dll
Is there a way to change things so I can access the deserialized content in the dynamic object using property names instead of as an associative array, without getting the exception?
I found this SO post on RutimeBinderExceptions:
Accessing properties of anonymous/dynamic types across dll boundaries gives RuntimeBinderException
But I'd prefer not to use the ExpandoObject type and I'm not even sure if it applies to my situation.
UPDATE: Ok, I believe I am having the problem of depicted in the reference SO post above. The context of the call is a callback from the CefSharp browser user control when Javascript calls back into my C# app.
Try working without the dynamic data type:
Dictionary<string, object> theData= new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonString);
string payload = (string)theData["payload"];
int number = (int)theData["number"];
string dialogResult = (string)theData["dialogResult"];
The call to Deserialize() creates a tree of Dictionary that you can traverse at will.

Deserialize the EventValidation object

I am trying to serialize and deserialize the event validation store. I have used code on MSDN to do the same with the viewstate. I cannot seem to get the data out of the EventValidation object.
System.Web.UI.LosFormatter los = new System.Web.UI.LosFormatter();
var t = los.Deserialize("/wEdAAXD48AAvF6Ff7P5UOQbT3VqkrDKlMWdnNXfGOHHYL4xn7VF+rYDddmo2pWyOYlEzR9ytSa0+vS8Kw5xkFTTwf/ogY5mU3PIFIVTnINRkldVDi8fjE6FJuo5OYrccfM1phFxAalSeL3MjHSQK44wYPDs")
HashSet<object> h = new HashSet<object>();
foreach (object d in t)
{
DoSomething()
}
System.Web.UI.EventValidationStore is the object type (?)
I have tried to use a hash set, a list, etc. I am new to this, and it is was out of what I know how do do, but would love to learn it.
The error I get is: "foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator'"
I could not find anything on MSDN about the System.Web.UI.EventValidationStore.
I apologize if this is a confusing post, I am just not sure how to ask it.
Update: I successfully deserialized one EventValidation base64 string, but others are proving to be elusive. The one in the code segment does not seem to work.
Summary:
I need to be able to decode/deserialize and encode/serialize the eventvalidation base64 string in .NET.
The __EVENTVALIDATION field structure is internal to ASP.NET and is subject to change. Trying to deserialize / serialize it is unsupported. The supported ways of interacting with it are via the Page's ValidateEvent and RegisterForEventValidation APIs.
What exactly are you trying to accomplish? Perhaps we can find a supported way of doing it.

"dynamic" keyword and JSON data

An action method in my ASP.NET MVC2 application returns a JsonResult object and in my unit test I would like to check that the returned JSON object indeed contains the expected values.
I tried this:
1. dynamic json = ((JsonResult)myActionResult).Data;
2. Assert.AreEqual(JsonMessagesHelper.ErrorLevel.ERROR.ToString(), json.ErrorLevel);
But I get a RuntimeBinderException "'object' does not contain a definition for 'ErrorLevel'".
However, when I place a breakpoint on line 2 and inspect the json dynamic variable (see picture below), it obviously does contain the ErrorLevel string and it has the expected value, so if the runtime binder wasn't playing funny the test would pass.
What am I not getting? What am I doing wrong and how can I fix this? How can I make the assertion pass?
You don't really need dynamic. Here's an example. Suppose you had the following action which you would like to unit test:
public ActionResult Index()
{
return Json(new { Id = 5, Foo = "bar" });
}
and the corresponding test:
// act
var actual = subjectUnderTest.Index();
// assert
var data = new RouteValueDictionary(actual.Data);
Assert.AreEqual(5, data["Id"]);
Assert.AreEqual("bar", data["Foo"]);
Also you might find the following blog post useful.
The Data property of the JsonResult is of type Object this means, although you have a dynamic declaration, the type that is set is still Object. The other issue is that you are using an anonymous type as the Data and then trying to access that as a declared instance outside of its applicable scope. Use #Darin's technique for accessing the property values using a RouteValueDictionary.

Categories