I am trying to bind a drop-down with these lists in my View. Not able to convert the below JSON collections to LISTS.
My JSON string is in this format:
["AppTypes",
[
{
"AppTypeID": "5136",
"AppType": "ABC"
},
{
"AppTypeID": "dca6",
"AppType": "MNO"
},
{
"AppTypeID": "d8de",
"AppType": "PQR"
}
],
"CompTypes",
[
{
"CompTypeID": "0425",
"CompType": "STU"
},
{
"CompTypeID": "0426",
"CompType": "EDC"
},
{
"CompTypeID": "0444",
"CompType": "PLM"
}
]
]
I am trying to deserialize the code, but not getting through. My Class,
public class DAL
{
public DAL() { }
public CompList CompList { get; set; }
}
public class CompList
{
public CompList()
{
AppTypes = new List<AppTypes>();
CompType = new List<CompTypes>();
}
public List<AppTypes> AppTypes;
public List<ComTypes> CompType;
}
public class AppTypes
{
public Guid AppTypeID { get; set; }
public string AppType { get; set; }
}
public class CompTypes
{
public Guid CompTypeID { get; set; }
public string CompType { get; set; }
}
public class JSONSerializer
{
public static T ConvertFromJSON<T>(String json)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<T>(json);
}
}
Controller Code:
dynamic obj = JSONSerializer.ConvertFromJSON<DAL>(JsonData);
Not able to get where I am going wrong. Any help would be really appreciated.
The main problem here is that your JSON represents a top-level array containing either strings or nested arrays containing objects, but you are trying to deserialize this into a top-level object - not an array. Your class design is quite reasonable, but a serializer such as JavaScriptSerializer isn't really designed to completely restructure a data model in this way during deserialization. You may need to deserialize into a more literal representation of the JSON, then restructure the data with, say, Linq.
A secondary problem is that you are declaring your ID properties to be Guids, but the corresponding JSON properties (such as "AppTypeID": "5136") do not have enough digits to be Guids. JavaScriptSerializer expects a Guid to have 32 digits, optionally separated by hyphens, e.g.: "d70d7583-b2e6-4f6e-8d99-2022d3ca2b10" or "d70d7583b2e64f6e8d992022d3ca2b10".
Thus, if I change your Guid properties to strings:
public class AppTypes
{
public string AppTypeID { get; set; }
public string AppType { get; set; }
}
public class CompTypes
{
public string CompTypeID { get; set; }
public string CompType { get; set; }
}
Then I can deserialize and convert to a CompList as follows:
var js = new JavaScriptSerializer();
var array = js.Deserialize<List<object>>(JsonData); // Deserialize outer array
var compList = new CompList
{
AppTypes = array
.OfType<IEnumerable<object>>() // Enumerate through nested arrays
.SelectMany(o => o) // Enumerate through elements in nested arrays
.OfType<IDictionary<string, object>>() // Pick out those which are JSON objects (deserialized as dictionaries)
.Where(d => d.ContainsKey("AppType")) // Filter those that are AppTypes
.Select(d => js.ConvertToType<AppTypes>(d)) // Deserialize to the AppTypes class
.ToList(),
CompType = array
.OfType<IEnumerable<object>>()
.SelectMany(o => o)
.OfType<IDictionary<string, object>>()
.Where(d => d.ContainsKey("CompType"))
.Select(d => js.ConvertToType<CompTypes>(d))
.ToList(),
};
FYI, your original code could deserialize JSON that looks like this into a CompList:
{
"AppTypes": [
{
"AppTypeID": "5136",
"AppType": "ABC"
},
{
"AppTypeID": "dca6",
"AppType": "MNO"
},
{
"AppTypeID": "d8de",
"AppType": "PQR"
}
],
"CompType": [
{
"CompTypeID": "0425",
"CompType": "STU"
},
{
"CompTypeID": "0426",
"CompType": "EDC"
},
{
"CompTypeID": "0444",
"CompType": "PLM"
}
]
}
Note that the outermost JSON is an object with two array-valued properties rather than an array of two strings and two arrays.
Related
I am trying to compare json value and based on that i want to update the existing value,for example, currently we have "value" : [r0] in json, i want to compare and if value : [r0] ,then update it to [r0,r1] but iam hiting error that it cannot compare and there is a cast issue, could someone suggest what could be done
public void updateJsonParameter(string file)
{
try
{
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
var jobject = JObject.Parse(file);
var ringvalue = (string)jobject["properties"]["parameters"]["ringValue"]["value"]; // unable to case here and compare
jobject["properties"]["parameters"]["ringValue"]["value"] = array; // able to update value but i want to update after comparing the existing values
var result = JsonConvert.SerializeObject(jobject);
}
following is the json format
{
"properties": {
"displayName": "jayatestdefid",
"description": "test assignment through API",
"metadata": {
"assignedBy": "xyz#gmail.com"
},
"policyDefinitionId": "/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters": {
"ringValue": {
"value": ["r0"]
}
},
"enforcementMode": "DoNotEnforce",
}
}
jobject.properties.parameters.ringValue.value is an array ["r0"] with one element "r0". If you want to check if it's an array with one element and that element is "r0", do exactly that:
var ringvalue = jobject["properties"]["parameters"]["ringValue"]["value"];
if(ringvalue.length == 1 && ringvalue[0] == "r0")
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
You could compare the ringvalue (which is an JArray) using JArray.DeepEquals and then replace if the comparison returns true. For example,
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
JArray valueToCompare = new JArray(new[]{"r0"});
var ringvalue = (JArray)jobject["properties"]["parameters"]["ringValue"]["value"];
if(JArray.DeepEquals(ringvalue,valueToCompare))
{
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
}
First, as Klaycon said in his answer, it's worth noting that your "value" is not a single string. In json, whenever you see [ and ] then you have a collection, or an array, or a list.
When I work with json strings, I always like to be able to convert them into a strongly typed object. There is a very handy online tool I use all the time: http://json2csharp.com/
I took your json string that you provided and pasted it into that website. Here is that your object(s) look like when converted into c# classes:
public class RootObject // You can name this whatever you want
{
public Properties properties { get; set; }
}
public class Metadata
{
public string assignedBy { get; set; }
}
public class RingValue
{
public List<string> value { get; set; }
}
public class Parameters
{
public RingValue ringValue { get; set; }
}
public class Properties
{
public string displayName { get; set; }
public string description { get; set; }
public Metadata metadata { get; set; }
public string policyDefinitionId { get; set; }
public Parameters parameters { get; set; }
public string enforcementMode { get; set; }
}
Now, we can easily do the logic you need as follows:
// This is your json string, escaped and turned into a single string:
string file = "{ \"properties\": { \"displayName\": \"jayatestdefid\", \"description\": \"test assignment through API\", \"metadata\": { \"assignedBy\": \"xyz#gmail.com\" }, \"policyDefinitionId\": \"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test\", \"parameters\": { \"ringValue\": { \"value\": [\"r0\"] } }, \"enforcementMode\": \"DoNotEnforce\", }}";
// Convert your json string into an instance of the RootObject class
RootObject jobject = JsonConvert.DeserializeObject<RootObject>(file);
// Get a list of all the "values"
List<string> values = jobject.properties.parameters.ringValue.value;
// Loop over your colleciton of "value" and do your logic
for (int i = 0; i < values.Count; ++i)
{
if (values[i] == "r0")
{
values[i] = "r0,r1";
}
}
// And finally, turn your object back into a json string
var result = JsonConvert.SerializeObject(jobject);
And this is the final result:
{
"properties":{
"displayName":"jayatestdefid",
"description":"test assignment through API",
"metadata":{
"assignedBy":"xyz#gmail.com"
},
"policyDefinitionId":"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters":{
"ringValue":{
"value":[
"r0,r1"
]
}
},
"enforcementMode":"DoNotEnforce"
}
}
I am trying to implement the json structure in c# objects and I am trying to understand how I can use the correct object depending on the type. For example:
public class RootObject
{
public string name { get; set; }
public Content content { get; set; }
}
public class Content
{
public string id{ get; set; }
public string type { get; set; }
public Dictionary<string, Item> child { get; set; }
}
public class Item
{
public string id { get; set; }
public string type { get; set; }
public List<string> model { get; set;}
public string[] color {get; set;}
}
Please note this is just an example there are more properties for each object. If Json contains type = "Boy" how can I generate the boy object.
Example JSON:
string json = #"
{
'name': 'Object 1',
'content': {
'body': {
'id': 'body',
'type': 'Body'
},
'style': {
'id': 'style',
'type': 'Style'
},
'DynamicName-123': {
'id': 'DynamicName-123',
'type': 'Row'
'model': {},
'colors': []
},
'DynamicName-434': {
'id': 'DynamicName-434',
'type': 'Column'
'model': {},
'colors': []
},
'DynamicName-223': {
'id': 'DynamicName-223',
'type': 'Item'
'model': {},
'colors': []
}
}
}";
If your key/value pair are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData] Read more
Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.
In your case, suppose there is a class,
public class MyClass
{
public string Qaz { get; set; }
public string Wsx { get; set; }
[JsonExtensionData]
public Dictionary<string, JToken> child { get; set; }
public MyClass()
{
child = new Dictionary<string, JToken>();
}
}
In the above class, you know that Qaz and Wsx are always present from your json either they contain value or null,
But for dynamic data, you can't say which key/value pair you will receive from your json so the [JsonExtensionData] can collect all those key/value pair in a dictionary.
Suppose the below classes will be for your dynamic data,
public class ABC
{
public string Abc { get; set; }
}
public class PQR
{
public string Pqr { get; set; }
}
public class XYZ
{
public string Xyz { get; set; }
}
Serialization:
ABC aBC = new ABC { Abc = "abc" };
PQR pQR = new PQR { Pqr = "pqr" };
XYZ xYZ = new XYZ { Xyz = "xyz" };
MyClass myClass = new MyClass();
myClass.Qaz = "qaz";
myClass.Wsx = "wsx";
myClass.child.Add("ABC", JToken.FromObject(aBC));
myClass.child.Add("PQR", JToken.FromObject(pQR));
myClass.child.Add("XYZ", JToken.FromObject(xYZ));
string outputJson = JsonConvert.SerializeObject(myClass);
This will give you json like
{
"Qaz": "qaz",
"Wsx": "wsx",
"ABC": {
"Abc": "abc"
},
"PQR": {
"Pqr": "pqr"
},
"XYZ": {
"Xyz": "xyz"
}
}
Deserialization:
MyClass myClass = JsonConvert.DeserializeObject<MyClass>(outputJson);
string Qaz = myClass.Qaz;
string Wsx = myClass.Wsx;
if (myClass.child.ContainsKey("ABC"))
{
ABC abcObj = myClass.child["ABC"].ToObject<ABC>();
}
if (myClass.child.ContainsKey("PQR"))
{
PQR pqrObj = myClass.child["PQR"].ToObject<PQR>();
}
if (myClass.child.ContainsKey("XYZ"))
{
XYZ pqrObj = myClass.child["XYZ"].ToObject<XYZ>();
}
Conclusion: The main aim of [JsonExtensionData] is to keep your json class hierarchy simple and more readable so you don't need to manage class structure for every property.
Get all dynamic data with the specific key in JToken inside Dictionary :
You can use LINQ to fetch all dynamic data of particular key from the above dictionary.
var allAbcTypes = myClass.child
.SelectMany(x => x.Value
.ToObject<JObject>()
.Properties()
.Where(p => p.Name == "Abc") //<= Use "Column" instead of "Abc"
.Select(o => new ABC //<= Use your type that contais "Column" as a property
{
Abc = o.Value.ToString()
})).ToList();
In your case, Its something like,
var allColumnTypes = myClass.child
.SelectMany(x => x.Value
.ToObject<JObject>()
.Properties()
.Where(p => p.Name == "Column")
.Select(o => new Item
{
id = x.Value["id "].ToString(),
type = x.Value["type "].ToString(),
model = x.Value["model"].ToObject<List<string>>(),
color = x.Value["color"].ToObject<string[]>()
})).ToList();
If you want to deserialize to a dictionary with a Key string and a dynamic value (boy or girl in this case), the only way I Know is using Dynamic class:
public List<Dictionary<string, dynamic>> child { get; set; }
Is there a way to declare a class where for a specific variable I can receive either a List or a string?
I trying to deserialize a JSON and it can come in one of the formats below:
"MercadoriasPresencaCarga": {
"Mercadoria": 7693066,
"Descarga": "08/07/2017 13:35:39"
},
or
"MercadoriasPresencaCarga": {
"Mercadoria": [
"7693066"
],
"Descarga": [
"08/07/2017 13:35:39"
]
},
The class for this block is created like this:
public class MercadoriasPresencaCarga
{
public List<string> Mercadoria { get; set; }
public List<string> Descarga { get; set; }
}
The problem is that if this block of JSON come as the first format that I showed where it is not a array, it will cause an error on it deserialization.
How could I solve this problem?
Ideally the json should always come in the same format, but if that's not a possibility there are some workarounds.
Both json strings will deserialize successfully using the following class:
public class Model
{
// other properties here
// ....
[JsonIgnore]
public string Mercadoria => GetValue("Mercadoria");
[JsonIgnore]
public string Descarga => GetValue("Descarga");
public JObject MercadoriasPresencaCarga { get; set; }
private string GetValue(string path)
{
if (MercadoriasPresencaCarga == null)
{
return null;
}
string value = null;
JToken token = MercadoriasPresencaCarga.SelectToken(path);
if (token.Type == JTokenType.Array && token.HasValues)
{
value = token.First.Value<string>();
}
else
{
value = token.Value<string>();
}
return value;
}
}
Please note that:
MercadoriasPresencaCarga will be deserialized as JObject
Both Mercadoria and Descarga are non-serializable properties (marked with [JsonIgnore])
Testing the code - json string with string properties (no arrays):
string json1 = #"{
""MercadoriasPresencaCarga"": {
""Mercadoria"": 7693066,
""Descarga"": ""08/07/2017 13:35:39""
}
}";
Model model1 = JsonConvert.DeserializeObject<Model>(json1);
Console.WriteLine($"Descarga: {model1.Descarga}, Mercadoria: {model1.Mercadoria}");
Testing the code - json string with arrays:
string json2 = #"{
""MercadoriasPresencaCarga"": {
""Mercadoria"": [
""7693066""
],
""Descarga"": [
""08/07/2017 13:35:39""
]
}
}";
Model model2 = JsonConvert.DeserializeObject<Model>(json2);
Console.WriteLine($"Descarga: {model2.Descarga}, Mercadoria: {model2.Mercadoria}");
How can I do JSON in C# like the data below ?
{
"Aliases": [ "teddy", "freddy", "eddy", "Betty" ],
"Name":"reacher gilt",
"Address":"100 East Way",
"Age":74,
"Bars": {
"items": [
{
"Sub_Property1":"beep",
"Sub_Property2":"boop"
},
{
"Sub_Property1":"meep",
"Sub_Property2":"moop"
},
{
"Sub_Property1":"feep",
"Sub_Property2":"foop"
}
]
}
}
Actually my problem is inside the sub-collection. I saw someone did something
like this
person.Bars.Add("items",
new List<BarClass>(new[]{
new BarClass("beep","boop"),
new BarClass("meep","moop"),
new BarClass("feep","foop"),
}));
So, I have to add new BarClass("beep","boop"), but I need to do something
like this
String [] no1 = {1,2,3}
String [] no2 = {4,5,6}
person.Bars.Add("items",
new List<BarClass>(new[]{
for ()
{
new BarClass(no1[i],no2[i])
}
}));
How can i do this? Thanks and please help..
To read the JSON
The best way to read the whole JSON is to Deserialize it to a native C# object. If you do not already have the classes with your, you can create it in Visual Studio as
Copy your JSON text
Create a new empty class file in VS
Edit > Paste Special > Paste JSON As Classes
Here are the classes
public class Person
{
public string[] Aliases { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Bars Bars { get; set; }
}
public class Bars
{
public Item[] items { get; set; }
}
public class Item
{
public string Sub_Property1 { get; set; }
public string Sub_Property2 { get; set; }
}
Now you can use some .NET JSON library to deserialize. JSON.Net aka Newtonsoft JSON is a great library. You get get it from NuGet as well.
Then it's pretty easy to get the C# object from the JSON
//using Newtonsoft.Json;
var jsonString = File.ReadAllText(#"C:\YourDirectory\person.json");
var person = JsonConvert.DeserializeObject<Person>(jsonString);
If you want to read the sub-collection only, you can rather use Linq-to-JSON to read the items directly, like this
//using Newtonsoft.Json.Linq;
var jObject = JObject.Parse(jsonString);
List<Item> details = jObject["Bars"]["items"].ToObject<List<Item>>();
To create the JSON
You first need to create the object, then Serialize to JSON
string[] subProperties1 = new string[] { "1", "2", "3" };
string[] subProperties2 = new string[] { "4", "5", "6" };
Person person = new Person { Name = "Johny", Age = 7, Address = "Earth", Aliases = new string[] { "Sony", "Monty" } };
person.Bars = new Bars {
items = subProperties1.Zip(subProperties2,
(prop1, prop2) => new Item { Sub_Property1 = prop1, Sub_Property2 = prop2 })
.ToArray() };
var json = JsonConvert.SerializeObject(person);
To create the items from your existing string arrays, I have used IEnumerable.Zip function from Linq. You can read about them here.
This is the created JSON data
{
"Aliases": [ "Sony", "Monty" ],
"Name": "Johny",
"Address": "Earth",
"Age": 7,
"Bars": {
"items": [
{
"Sub_Property1": "1",
"Sub_Property2": "4"
},
{
"Sub_Property1": "2",
"Sub_Property2": "5"
},
{
"Sub_Property1": "3",
"Sub_Property2": "6"
}
]
}
}
You should create some classes
public class Person
{
public string Name {get;set;}
public string Address{get;set;}
public int Age {get;set;}
public Header {get;set;}
}
public class Header
{
public Detail[] Details {get;set;}
}
public class Detail
{
public string Sub1 {get;set;}
public string Sub2 {get;set;}
}
Create instance from Person class and initialize to instance after than
JavaScriptSerializer serializer =new JavaScriptSerializer();
var result=serializer.Serialize(instanceOfPerson);
"result" is json data
Assuming that you mean you want to create JSON string, you need to create those classes and use something like Newtonsoft JSON.net:
public class Item
{
public string Sub_Property1 { get; set; }
public string Sub_Property2 { get; set; }
}
public class Bars
{
public List<Item> items { get; set; }
}
public class Person
{
public List<string> Aliases { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Bars Bars { get; set; }
}
Please read the documentation here: http://www.newtonsoft.com/json/help/html/Introduction.htm
I'm trying to use JSON.NET to deserialize a response from a third-party web service. This is the full code of my (contrived) example showing what I'm trying to do:
namespace JsonNetTests
{
public enum Parameter
{
Alpha = 1,
Bravo = 2,
Charlie = 3,
Delta = 4
}
public class ResponseElement
{
public int Id { get; set; }
public string Name { get; set; }
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public Parameter[] Parameters { get; set; }
}
public class ResponseBody
{
public string Locale { get; set; }
public string[] Errors { get; set; }
public ResponseElement[] ResponseElements { get; set; }
}
[TestFixture]
public class JsonNetTest
{
[Test]
public void TestEnumArray()
{
string jsonResponse = #"
{""ResponseBody"": {
""Locale"": ""en-US"",
""Errors"": [],
""ResponseElements"": [{
""Id"": 1,
""Name"": ""ABC"",
""Parameters"" : {
""Parameter"" : ""Alpha""
},
}, {
""Id"": 2,
""Name"": ""BCD"",
""Parameters"" : {
""Parameter"" : ""Bravo""
},
}
]
}}
";
JObject rootObject = JObject.Parse(jsonResponse);
JToken rootToken = rootObject.SelectToken("ResponseBody");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MissingMemberHandling = MissingMemberHandling.Error;
ResponseBody body = JsonConvert.DeserializeObject<ResponseBody>(rootToken.ToString(), settings);
foreach (var element in body.ResponseElements)
{
Console.WriteLine(string.Format("{0}: {1}", element.Id, element.Name));
foreach (var parameter in element.Parameters)
{
Console.WriteLine(string.Format("\t{0}", parameter));
}
}
}
}
}
I get the following exception:
Newtonsoft.Json.JsonSerializationException : Cannot deserialize JSON object (i.e. {"name":"value"}) into type 'JsonNetTests.Parameter[]'.
The deserialized type should be a normal .NET type (i.e. not a primitive type like integer, not a collection type like an array or List) or a dictionary type (i.e. Dictionary).
To force JSON objects to deserialize add the JsonObjectAttribute to the type. Path 'ResponseElements[0].Parameters.Parameter', line 9, position 21.
I tried to use the ItemConverterType attribute to specify how the array should be deserialised:
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
But this does not help either. Can someone advise?
You're trying to stuff an object into an array. ResponseElement.Parameters is an array of enums where you're json code is using an object to describe each parameter.
Your json looks like this:
// some json
"Parameters" : {
"Parameter" : "Alpha"
},
// more json
But to translate it into an array of enums it should look like this:
// some json
"Parameters" : [ "Alpha", "Bravo" ],
// more json
If you can't change the json, you can change your model as so:
public enum ParameterEnum
{
Alpha = 1,
Bravo = 2
}
public ParameterContainer
{
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public ParameterEnum Parameter {get;set;}
}
public class ResponseElement
{
public int Id { get; set; }
public string Name { get; set; }
public ParameterContainer[] Parameters { get; set; }
}
Effectively, you'll serialize the json into an array of ParameterContainers which will expose their values.