1669

Casting objects from JSON array to custom classes in C#

Question:

I am using Visual Studio's auto generated REST Web Application project structure to create a RESTful API that consumes a JSON input.

Without going into too much detail, I have attempted to define a JSON structure like these:

Example 1:

"operation": { "type": "EXIST", "args": [ { "ColumnName": "SomeColumnA", "Row": 2 } ] }

Example 2:

"operation": { "type": "ADD", "args": [ { "type": "ADD", "args": [ { "columnName": "SomeColumnB", "row": 12 }, { "columnName": "SomeColumnC", "row": 18 } ] }, 20 ] }

operation represents one of any number of basic database operations and the arguments for those operations. In my first example, the operation is EXIST, which should check a database cell to see if a value exists or not. The args for this operation is simply an object that contains the column and row information for the cell to check (I call this a Value). In my second example, the function is ADD, which should add two values together and return the sum. Here, the arguments are a constant of 20 and a nested ADD function, which itself takes two Values. So, in general, the args array can take either primitive values, another nested operation, or a pair of values that represents a cell to read the actual value from. The ultimate goal here is to create a general structure that would allow me to nest combinations of functions, cell values, and constants to create compound functions like Average or Sum.

In my Models folder, I have the following classes to cast my data to:

public class Instruction { public Operation[] Operations { get; set; } } public class Operation { public string Type { get; set; } public object[] Args { get; set; } } public class Value { public string ColumnName { get; set; } public int Row { get; set; } }

Note that the Args in Operation is of type object[].

When I call my web application by POSTing this JSON to it, C# automatically parses the JSON into objects defined in my Models folder. Say we used Example 1:

[HttpPost] public IHttpActionResult Foo(Instruction instruction) { foreach(Operation op in instruction.Operations) { switch (op.Type) { case "EXIST": Console.WriteLine("exist"); // works fine // since we got here, expect Args[0] to be type 'Value' var value = (Value) op.Args[0]; // InvalidCastException // logic for EXIST case "ADD": // logic for ADD // ... } } }

It's casting Operation just fine, and I get Type out correctly. I also get Args as an object[] with a lone element in it. But if I try to cast it to Value, it refuses to cast properly.

My question after all of this is: what is the best way to achieve what it looks like I'm attempting to do here? Am I on the right track? If so, what is my error? If I'm going about this the wrong way, what is a better practice alternative? Note that since I'm using Visual Studio's out-of-the-box Web Application framework I don't seem to have access to the function that deseralizes the JSON, so I don't think I can build a custom deserializer.

Answer1:

See this fiddle that shows how I would use the dynamic type.

<a href="https://dotnetfiddle.net/7Czubl" rel="nofollow">Fiddle</a>

public static void Main() { var json = @"{""operation"": { ""type"": ""ADD"", ""args"": [ { ""type"": ""ADD"", ""args"": [ { ""columnName"": ""SomeColumnB"", ""row"": 12 }, { ""columnName"": ""SomeColumnC"", ""row"": 18 } ] } ] }}"; dynamic data = JsonConvert.DeserializeObject(json); Console.WriteLine(data.operation.type.ToString()); Console.WriteLine(data.operation.args[0].args[0].columnName.ToString()); Console.WriteLine((int)data.operation.args[0].args[0].row); }

Recommend

  • How to write string.Contains(someText) in expression Tree
  • What do I do with this error when I run tests in rails?
  • What causes the runtime difference in this trivial fortran code?
  • Azure webjobs output logs indexing taking very long
  • R convert summary result (statistics with all dataframe columns) into dataframe
  • NUnit 3.0 TestCase const custom object arguments
  • Approximate Order-Preserving Huffman Code
  • Center align outputs in ipython notebook
  • Laravel: Getting Session ID oddly truncates when using foreach
  • How to disable all widgets inside Panel or inside Composite?
  • Reduction and collapse clauses in OMP have some confusing points
  • ADO and msqli connections very slow
  • Grails calculated field in SQL
  • custom UITableViewCell with image for highlighting
  • Marklogic : Query response time is very high
  • Time complexity of a program which involves multiple variables
  • How to use remove-erase idiom for removing empty vectors in a vector?
  • Is possible to count alias result on mysql
  • Sending data from AppleScript to FileMaker records
  • vba code to select only visible cells in specific column except heading
  • Convert array of 8 bytes to signed long in C++
  • Angular 2 constructor injection vs direct access
  • Understanding cpu registers
  • Java static initializers and reflection
  • Change div Background jquery
  • Android Google Maps API OnLocationChanged only called once
  • How does Linux kernel interrupt the application?
  • Django query for large number of relationships
  • Busy indicator not showing up in wpf window [duplicate]
  • Recursive/Hierarchical Query Using Postgres
  • Running Map reduces the dimensions of the matrices
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • Binding checkboxes to object values in AngularJs
  • How can I use `wmic` in a Windows PE script?
  • UserPrincipal.Current returns apppool on IIS
  • Why do underscore prefixed variables exist?
  • Net Present Value in Excel for Grouped Recurring CF
  • How to push additional view controllers onto NavigationController but keep the TabBar?
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize
  • How to load view controller without button in storyboard?