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.
See this fiddle that shows how I would use the dynamic type.
Fiddle
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);
}
Related
I'm working on an ASP .NET core web api where I'm trying to create a model in C# based on a JSON that can have dynamic properties.
The type field can be of 3 types: Land, Water, Air.
Based on the type, the corresponding properties in the "source" would be different.
For example. if the type is "Land", there would be an additional property in source called "speed". If the type is "Air", there would be 2 additional properties in source called "Height" and "NumberLandings".
The modify property is an array that can have different types of modifications - Performance/Aesthetic/Functional...., and based on the modification type, I can have different properties underneath for that modification.
For example, if the type is "Performance", there would be additional properties such as brakes/turbo/suspension.
{
"properties": {
"source": {
"type": "Land",
"speed": "160mph"
},
"modify ": [
{
"type": "Performance",
"brakes": "",
"turbo": "",
"suspension": ""
},
{
"type": "Functional",
"electric": "",
"applications": "Carplay"
}
]
}
}
Question: How can I construct my C# class/model for the dynamic JSON? I'm thinking to keep the source type and modification type as an enum, and based on the enum type, define the other parameters.
I don't want to define all the properties and end up having some of them as null, like below:
[DataContract]
public class Source
{
[DataMember]
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[DataMember]
[JsonProperty(PropertyName = "speed")]
public string Speed{ get; set; }
[DataMember]
[JsonProperty(PropertyName = "height")]
public string Height{ get; set; }
[DataMember]
[JsonProperty(PropertyName = "NumberLandings")]
public string NumberLandings { get; set; }
}
The type field can be of 3 types: Land, Water, Air. Based on the type, the corresponding properties in the "source" would be different.
This is essentially polymorhism, and there are existing questions and articles regarding this. This might require a custom jsonConverter class, and it might be easier if you format your message to have a separate object, rather than loose properties, i.e:
"type": "Land",
"MyBaseObject":{
"speed": "160mph"
}
The modify property is an array that can have different types of modifications - Performance/Aesthetic/Functional...., and based on the modification type, I can have different properties underneath for that modification.
This sounds like a key-value store, and may use the same approach to polymorphism as above to store different properties for different kinds of objects, i.e. it could be represented by a Dictionary<string, MyModificationBase>.
Keep in mind that you still need to use the object model somehow, preferably without needing do typechecking all over the place.
I have a scenario where I receive json as a string. Each piece of json is formatted the same, except for a collection of items within. Take this as simplified examples:
{
"Type": "A",
"Items": [
{ "Name": "Item 1" },
{ "Name": "Item 2" }
]
}
{
"Type": "B",
"Items": [
{ "Counter": 1 },
{ "Counter": 2 }
]
}
I have the following models in code to represent this:
public enum Type
{
A, B
}
public class InstanceTypeA
{
public string Name { get; set; }
}
public class InstanceTypeB
{
public int Counter { get; set; }
}
note: in the future, the types will be extended further, say to D, E, and F for this example. All of which will have an item collection structured differently again.
And I would like to deserialize this into a model, for example:
public class Container<T>
{
public Type Type { get; set; }
public List<T> Items { get; set; }
}
where T would be either instanceTypeA or instanceTypeB
As mentioned, I receive the json shown at the top as a string. And it's the "type" enum that dictates the type of the object held in the items collection. I'm struggling to find a very generic way to implement this serialization.
I was thinking the factory pattern could help but not sure how to implement this - has anyone tackled a similar problem.
In my code, I happen to know if it's type A, B etc before actually attempting serialization. I could do this:
switch(obj.Type)
{
case A: JsonConvert.DeserializeObject<Container<A>>(obj.Json)
case B: JsonConvert.DeserializeObject<Container<B>>(obj.Json)
}
The drawback of this approach is that the calling code needs to then know its dealing with Container<A> or Container<B> etc. Which isn't generic at all. I can't get A or B to implement a common interface as they are both completely different. Bit stumped with this - I was hoping Factory pattern could help but can't see how - has anyone dealt with a similar issue before?
Thanks for any pointers in advance!
You don't want to use the Type property to dictate what type is used. When using the Newtonsoft Json serializer, you can include the type of an object in the JSON document. That way, when the serializer deserializes the string, it will understand what types to use. So you could completely drop the Type property and just check the type of object in the array. I believe you need to set the TypeNameHandling property of the settings object passed into the serializer. Once you see the serializer outputting a $type property with your objects in the JSON string, you know that you've done it right.
I am serializing objects to json using Json.NET. However, certain properties of my object are objects themselves that contain quite a lot of additional information, so my json output is very cluttered and hard to interpret. Ideally, I would like to show that these specific properties exist (show the object type) but without fully serializing them.
For example, instead of:
{
"sport": "football",
"popular": true,
"rules": [
{
"highSchool":
{
...
}
},
{
"college":
{
...
}
},
{
"nfl":
{
...
}
}
]
}
I would like to show:
{
"sport": "football",
"popular": true,
"rules": {Sports.Football.Rules}
}
Is this possible? I have tried using [JsonIgnore] in my Rules class for the rules property, but this ignores the rules property entirely instead of including but not serializing the property's object. I also read that [JsonProperty] and [JsonIgnore] are static and cannot be conditionally set, so that seems to rule out an alternative approach of selectively serializing the property (such as if Verbose is provided).
I want to access some address of pictures in a JSON, but the field name is a number and in c# a number is not a valid name for a variable...
My JSON:
{
"id":3441,
"name":"test",
"address": {
"1":"url.com\/45.jpg",
"2":"url.com\/23.jpg",
"3":"url.com\/65.jpg",
"4":"url.com\/789.jpg",
},
"count":2
}
My code in C#: (HrmlResult is my JSON)
dynamic stuff1 = Newtonsoft.Json.JsonConvert.DeserializeObject(HtmlResult);
string address= stuff1.address; //It Works
string allPics = stuff1.pic; //It Works
firstPicTextBox.Text= stuff1.pic.1; //compiler Error
secondPicTextBox.Text = stuff1.pic[2]; //runtime Error
What should I do?!
Thank you all...
You have to create Model object with properties, as in found json you're expecting.
Then, for number properties, you can use JsonProperty attribute to name the property as number, for example:
class MyModel {
[JsonProperty("2")]
public string Two {get; set;}
}
and then use DeserializeObject<MyModel> version
This is simplified example, for your object you have to maintain the hierarchy and probably have another class for 'address' property and use it as property type in the main model.
If you're able to modify the JSON, that's your best bet. What you have seems like it should be in an array:
{
"id":3441,
"name":"test",
"address":[
"url.com\/45.jpg",
"url.com\/23.jpg",
"url.com\/65.jpg",
"url.com\/789.jpg"
],
"count":2
}
From there, your address is a simple array of strings, rather than a numbered key-value pair collection.
I am sort of new to C# programming and am having trouble with the dictionary using .net 4.0.
I have sent a JSON object through JavaScriptSerializer into a Dictionary<string, object> object which worked great at extracting all the data.
JSON chain
{
"name" : "MrMonkey",
"type" : "monkey",
"location" : {
"id" : "125235",
"name" : "zoo"
},
"owner" : {
"id" : "4211",
"name" : "Biggles"
}
}
In this dictionary object created I have daughter levels that store information I need to extract from the dictionary and store elsewhere. Say I want is to extract the location name. As you can see it also shares a keyname with the parent level and another daughter level.
For the parent level I can extract information as simply as contact.name = dict["name"].ToString(); but how would I go about extracting the required information from the daughter levels?
I was able to create a work around in JSON.net to get this to work with a little bit of fiddling by checking the datatype and then converting it if it fell within a certain type, but this was aggravating and I been told by the boss not to use JSON.net.
Without having tried, I'd try something like: (dict["location"] as Dictionary<string,object>)["name"], as I'd presume from the JSON you've provided, that the daughters themselves are again deserialized into Dictionarys.
Anyway, the debugger will help you a lot here. If you set a breakpoint on the line after the call to the deserialization, you can inspect your dictionary (point the mouse to it and wait a second) and have a look at how your structure is now stored in C# objects.
I would try to create a class that would fill it with the json result. Then work normally and if need be, serialized into json again.
public class MyObject
{
public string name { get;set; }
public string type { get;set; }
public Location location { get;set; }
public Owner owner { get;set; }
}
public class Location
{
public int id { get;set; }
public string name { get;set; }
}
public class Owner
{
public int id { get;set; }
public string name { get;set; }
}
Have you tried using dict["location"]["name"]?
I assume that the daughter level is just treated as another dictionary stored in the parent one...