Merge objects to obtain a unique json object in MVC 4 - c#

I'm trying to serialize an object in a different way that the default serialization does.
I have a list of objects like this:
public class PausesByAgentModel
{
public PausesByAgentModel()
{
this.Pauses = new Dictionary<string, string>();
}
[DisplayName( "Agent" )]
public string AgentFullName { get; set; }
public Dictionary<string, string> Pauses { get; set; }
}
This object contains the different pauses for a Agent an the time for each pause in a dictionary because the pauses reasons are are dynamics (Key: Pause name, Value: Time in string format).
If I serialize this object as JsonResult to return it in my controller method, I get the following json:
{
"data" : [
{
"AgentFullName" : "John Doe",
[
{ "Break": "00:15:31" },
{ "Launch" : "01:01:23" },
{ "Mail" : "00:05:12" }
]
} ]
}
But I need that the pauses were placed like properties of the same object like this one:
{
"data" : [
{
"AgentFullName" : "John Doe",
"Break": "00:15:31",
"Launch" : "01:01:23",
"Mail" : "00:05:12"
} ]
}
I can't change the class design. So, I need to serialize the object in a different way as default design.
There is a way to merge or serialize the object like the second example?
Thanks.

As #qamar says on the comments, use a dynamic type.
public List<dynamic> ParseData(PausesByAgentModel model){
List<dynamic> result = new List<dynamic>();
foreach(String key in model.Keys){
result.Add(new { pauses = key,value = model[key] });
}
return result;
}

Related

JSON.NET Deserializing a JSON into a dictionary comes back as null

I have this JSON:
{
"AAPL": { "price": "131.85000" },
"eur/usd": { "price": "1.06290" },
"msft": { "price": "238.76000" }
}
When I try to deserialize this into a dictionary it comes back as null.
I am using the TwelveDataAPI.
https://twelvedata.com/docs#real-time-price
I have tried creating a simple class that will allow me to deserialize this JSON even if there are different tickers and different amounts of them.
My class:
public class CurrentPriceClass
{
public class Root
{
public Dictionary<string, Price> Prices { get; set; }
}
public class Price
{
public string price { get; set; }
}
}
But when I try to deserialize it, it comes back as null, and I cannot iterate over it:
CurrentPriceClass.Root priceRoot = JsonConvert.DeserializeObject<CurrentPriceClass.Root>(
dataJson);
foreach (KeyValuePair<string, CurrentPriceClass.Price> price in priceRoot.Prices)
{
Console.WriteLine($"{price.Key}: {price.Value.price}");
}
The error I get when iterating is:
Object reference not set to an instance of an object.
When debugging priceRoot is null.
I am assuming that this is a problem with my class.
Deserialize as Dictionary<string, CurrentPriceClass.Price> without needing the root class (CurrentPriceClass).
Dictionary<string, CurrentPriceClass.Price> priceRoot = JsonConvert.DeserializeObject<Dictionary<string, CurrentPriceClass.Price>>(dataJson);
foreach (KeyValuePair<string, CurrentPriceClass.Price> price in priceRoot)
{
Console.WriteLine($"{price.Key}: {price.Value.price}");
}
Demo # .NET Fiddle

Is there a way to dynamically switch fields from a model in the JSON representation of an object?

I've got a JSON representation of an object along with the relevant model classes listed below. The two classes MinionSettings and LeeSettings are derived classes from a base abstract generic class.
{
"charSetting": {
"minionSettings": {
"key": "minionSettings",
"value": [1,2,3]
},
"leeSettings": {
"key": "leeSettings",
"value": [
{
"baseAD": 1,
"baseAP": 1,
"visible": true
}
]
}
}
}
public class CharacterSettingsWrapper
{
public CharacterSettings CharSetting { get; set; }
}
public class CharacterSettings
{
public MinionSettings MinionSettings { get; set; }
public LeeSettings LeeSettings { get; set; }
}
[DataContract]
public class MinionSettings : CharacterSetting<List<int>>
{
public MinionSettings()
{
Key = "minionSettings";
Value = new List<int>();
}
}
public class LeeSettings : CharacterSetting<List<LeeSetting>>
{
public LeeSettings()
{
Key = "leeSettings";
Value = new List<LeeSetting>();
}
}
Is there any way to keep all the fields in the CharacterSettings class but have them removed from the JSON representation of the object while keeping the relevant key/value pair, so I'd like the JSON to look like below. If not, is there anything else that I could do to achieve this?
I've tried using my base abstract class but since its abstract, I can't make an instance of it so it doesn't quite work, and this data is being extracted from a JSON and then put into a relevant object which based on the derived classes (like the two classes MinionSettings and LeeSettings)
{
"charSetting":[
{
"key":"minionSettings",
"value":[
1,
12,
3
]
},
{
"key":"leeSettings",
"value":[
{
"baseAD":1,
"baseAP":1,
"visible":true
}
]
}
]
}
You can solve this problem purely by using JObject and JArray objects without the need to create and use any domain objects.
In the bellow code I've assumed that the nodes exist (to keep the code simple) but in production code please prefer TryGetValue (Ref) over the index operator (Ref).
//Retrieve the nodes from the original json
var json = File.ReadAllText("sample.json");
var root = JObject.Parse(json);
var charSetting = root["charSetting"];
var minionSettings = charSetting["minionSettings"];
var leeSettings = charSetting["leeSettings"];
//Construct the new json based on the retrieved values
var newcharSetting = new JArray();
newcharSetting.Add(minionSettings);
newcharSetting.Add(leeSettings);
var newRoot = new JObject();
newRoot.Add("charSetting", newcharSetting);
Console.WriteLine(newRoot.ToString());
I also have to mention that this code heavily relies on the sample json's structure. So, it is not generic enough to handle any kind of structure which resembles to this.
The printed output would look like this:
{
"charSetting": [
{
"key": "minionSettings",
"value": [
1,
2,
3
]
},
{
"key": "leeSettings",
"value": [
{
"baseAD": 1,
"baseAP": 1,
"visible": true
}
]
}
]
}

JSON serialization of an object with a variable length using JsonConvert in .net

I need help with some JSON serialization using the .NET/Newtonsoft JsonConvert.SerializeObject method. I have a class which I am using to store the variables that are outbound, called JSONVars.
My question is about how to handle the "Answer" variables in the below sample.
The first and last names always have one return in the loop, so that's easy. However the Answer part could have multiple returns in a loop.
A theoretical outbound JSON string would look like:
{
"FirstName" : "John",
"LastName" : "Doe",
"FavoriteVacation" : "Beach",
"FavoriteState" : "FL"
.....
}
with the "..." representing 1 to n possible returns in the loop.
As you can see, the place that I'm sending the JSON string needs to have it all in one comma delimited string that is properly formatted JSON, so I can't send the Answer block as a JSON array, like this (it will fail):
{
"FirstName" : "John",
"LastName" : "Doe",
"Answers" : [
"FavoriteVacation" : "Beach",
"FavoriteState" : "FL" .....
}
How can I adjust this so that I can "add" to the json serialized string 1 to n "answer" blocks?
Here is my code:
public class JSONVars
{
public string FirstName;
public string LastName;
//??? public string Answer;
}
static void Main(string[] args)
{
foreach (var objReturn in objlst)
{
JSONVars jsonvars = new JSONVars();
jsonvars.FirstName = objReturn.FirstName;
jsonvars.LastName = objReturn.LastName;
foreach (var answerobj in objReturn.SurveyAnswers)
{
if (answerobj.Vacation != null)
{
foreach (var answerobjVaca in answerobj.Vacation)
{
//???????
//answerobjVaca.QuestionText;
//answerobjVaca.AnswerText;
}
}
}
var jsonHolder = JsonConvert.SerializeObject(jsonvars);
}
}
The jsonHolder var is what is being sent out to an external service and needs to be properly serialized for JSON transmission.
Please note some code (like how objReturn is populated) left out for brevity.
The quick and easy solution is to use a Dictionary<string, object> in place of JSONVars. So you do something like this:
var dict = new Dictionary<string,object>();
dict["FirstName"] = objReturn.FirstName;
dict["LastName"] = objReturn.LastName;
foreach (var answerobj in objReturn.SurveyAnswers)
{
// it's not entirely clear where you are getting the JSON
// property names from, but assuming `QuestionText` gives you the property name
// Otherwise, adjust as necessary...
dict[answerObj.QuestionText] = answerObj.AnswerText;
}
The more complicated solution would be to write a custom converter (which isn't that hard). Then you could have your JSONVars class look like this:
public class JSONVars
{
public string FirstName;
public string LastName;
public Dictionary<string,object> Answers;
}
And use your custom converter to flatten Answers into your JSON string.
you must do like this
{
"FirstName" : "John",
"LastName" : "Doe",
"Answers" : [
{
"Question":"FavoriteVacation",
"Answer":"Beach"
},
{
"Question": "FavoriteState",
"Answer":"FL"
}, ...
]
}

What is the correct way to parse this JSON object in C#?

This is the JSON object I am receiving from a GET request:
{
"data": {
"valve_maker": [],
"water_volume": [
"15L",
"20L",
"..."
],
"cylinder_manufacturer": [
"Tianhai"
],
"qc_stamp": [
"TS"
],
"reference_standard": [
"GB 5099"
],
"production_licence": [
"TS2210752-2016"
],
"valve_production_licence": [
"TSF210030"
],
"rate_of_residual_deformation": {
"1": "<3%",
"2": "<10%"
},
"material_number": {
"1": "30CrMo",
"2": "34CrMo4",
"3": "..."
},
"heat_treatment": {
"1": "...",
"2": "..."
},
"drawing_number": {
"1": "...",
"2": "..."
},
"cylinder_thickness": []
}
right now, I am able to parse JSON objects with a simpler structure like :
{
"data": [
{
"gas_id": "ID of the gas",
"gas_name": "Gas name"
}
]
by using something like this:
private void jsonparsegas(string res)
{
JObject par = JObject.Parse(res);
foreach (JToken data in par["data"].Children())
{
string id = data["gas_id"].ToString();
string name = data["gas_name"].ToString();
if (this.cmbCylType.Items.Contains(name) == false)
{
this.cmbCylType.Items.Add(name);
}
}
}
When I try to apply the same thing to the more complicated JSON object, I get an error:
private void jsonparsecoc(string res)
{
//JObject par = JObject.Parse(res);
var jObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(res);
foreach (var child in jObj["data"].Children())
{
string vMaker = child["valve_maker"].ToString(); //error thrown here right away
string wVolume = child["water_volume"].ToString();
string cMan = child["cylinder_manufacturer"].ToString();
string QC = child["qc_stamp"].ToString();
string rStandard = child["reference_standard"].ToString();
string pLicence = child["production_licence"].ToString();
string VPL = child["valve_production_licence"].ToString();
string rrd = child["rate_of_residual_deformation"].ToString();
string mNum = child["material_number"].ToString();
string hTreatment = child["heat_treatment"].ToString();
string dNum = child["drawing_number"].ToString();
string cThick = child["cylinder_thickness"].ToString();
}
Cannot access child value on Newtonsoft.Json.Linq.JProperty
I have tried a few different things I found on StackOverflow, but I don't really understand how Deserializing of the objects works. The simpler parsing works just fine, and allows me to add all "gas_name"s that I receive from my GET request to a combobox. The format the first "valve_maker" child of "data" seems to have the same structure as "gas_id" or "gas_name" in the more similar JSON object, but this is where I receive the error right away. If I had to guess at a cause for the error, I'd say it has something to do with the difference between using
"valve_maker": []
and using
"gas_id": "ID of the gas"
in the objects. also I notice "data" is followed by [] brackets in the simpler one, and {} in the more complicated one.
If anyone could link to some good reading material, or offer a good explanation of a solution/what's going on, I'd really appreciate it.
This part is the key to the problem you're having:
in the objects. also I notice "data" is followed by [] brackets in the simpler one, and {} in the more complicated one.
In JSON,
[] brackets enclose an array
{} brackets enclose an object
In both code examples, you are digging into the object by looping through the results using par["data"].Children(). To be consistent with the JSON model, JSON.NET defines different behavior for resolving children of objects and arrays. The children of an object are its properties and the children of an array are its items.
In your code, the input to jsonparsegas is an array of simple objects with 2 properties where the input to jsonparsecoc is a single complex objects with many properties.
In jsonparsegas, the Children() call gives you an array of all the simple gas objects. You loop through these objects and extract the values of "gas_id" and "gas_name" for each object. In your example data, there only happens to be one gas object so your code only executes once.
In jsonparsecoc, the Children() call actually gives you property values for the properties of the complex object, since the result is an object and not an array. So, when you loop through this result you can't access things like "valve_maker", because they are defined on the complex object and you have already stepped into the value for valve_maker then this executes.
The solution is simple. Don't loop through the properties in jsonparsecoc. Instead of foreach(var child in jObj["data"].Children()) you need something like var child = jObj["data"];. This will give you the reference to the object that actually contains each of the properties you are trying to access.
#smartcaveman did a good job of explaining what is going wrong with your code. However, you might find your data a little easier to process if you defined strongly-typed classes for it like this:
class RootObject
{
public Data Data { get; set; }
}
class Data
{
[JsonProperty("valve_maker")]
public List<string> ValveMaker { get; set; }
[JsonProperty("water_volume")]
public List<string> WaterVolume { get; set; }
[JsonProperty("cylinder_manufacturer")]
public List<string> CylinderManufacturer { get; set; }
[JsonProperty("qc_stamp")]
public List<string> QCStamp { get; set; }
[JsonProperty("reference_standard")]
public List<string> ReferenceStandard { get; set; }
[JsonProperty("production_licence")]
public List<string> ProductionLicense { get; set; }
[JsonProperty("valve_production_licence")]
public List<string> ValveProductionLicense { get; set; }
[JsonProperty("rate_of_residual_deformation")]
public Dictionary<string, string> RateOfResidualDeformation { get; set; }
[JsonProperty("material_number")]
public Dictionary<string, string> MaterialNumber { get; set; }
[JsonProperty("heat_treatment")]
public Dictionary<string, string> HeatTreatment { get; set; }
[JsonProperty("drawing_number")]
public Dictionary<string, string> DrawingNumber { get; set; }
[JsonProperty("cylinder_thickness")]
public List<string> CylinderThickness { get; set; }
}
You can deserialize the JSON to your classes like this:
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
Demo here: https://dotnetfiddle.net/p0D7ze
public class Test{
public Data data{get;set;}
}
public class Data{
public List<string> Value_maker{get;set;}
public List<String> Water_Volume{get;set;}
public List<String> cylinder_manufacturer{get;set;}
}
Create Class structure Like that and after that use to deserialize
Jsonconvert.DeserializeObject(JsonString)
it will convert json into proper object, keep in mind structure should be proper and property name should be same as your json property
Hope It will Help you

Best approach in C# to deserialize json object that can be array or single object [duplicate]

This question already has answers here:
How to handle both a single item and an array for the same property using JSON.net
(9 answers)
Closed 4 years ago.
We're dealing with an json API result. Just to make our lives difficult the provider of the API returns on of the items as an array if there are multiple objects, or as a single object if there is only one.
e.g.
If there is only one object...
{
propertyA: {
first: "A",
second: "B"
}
}
Or if there are multiple:
{
propertyA: [
{
first: "A",
second: "B"
},
{
first: "A",
second: "B"
}
]
}
Does anybody have a good way of dealing with this scenario?
Ideally we'd like to serialize both to
public class ApiResult{
public ApiItem[] PropertyA {get;set;}
}
This works for the second example but of you encounter the first example you get a A first chance exception of type 'System.MissingMethodException' occurred in System.Web.Extensions.dll
Additional information: No parameterless constructor defined for type of 'ApiItem[]'.
I assume the class definition is as below
public class ApiResult
{
public ApiItem[] PropertyA { get; set; }
}
public class ApiItem
{
public string First { get; set; }
public string Second { get; set; }
}
You can deserialize the json into a dynamic variable, then check the type of d.propertyA. If it's JArray then propertyA is an array, so you can deserialize the json into a ApiResult. If it's JObject then propertyA is a single object, so you need to manually construct ApiItem and assign it to PropertyA of ApiResult. Consider the method below
public ApiResult Deserialize(string json)
{
ApiResult result = new ApiResult();
dynamic d = JsonConvert.DeserializeObject(json);
if (d.propertyA.GetType() == typeof (Newtonsoft.Json.Linq.JObject))
{
// propertyA is a single object, construct ApiItem manually
ApiItem item = new ApiItem();
item.First = d.propertyA.first;
item.Second = d.propertyA.second;
// assign item to result.PropertyA[0]
result.PropertyA = new ApiItem[1];
result.PropertyA[0] = item;
}
else if (d.propertyA.GetType() == typeof (Newtonsoft.Json.Linq.JArray))
{
// propertyA is an array, deserialize json into ApiResult
result = JsonConvert.DeserializeObject<ApiResult>(json);
}
return result;
}
The code above will return an instance of ApiResult for both json examples.
Working demo: https://dotnetfiddle.net/wBQKrp
Building upon ekad's answer, I made the code:
Shorter: as now you don't have map one by one every property inside ApiItem
Probably faster in the case of being already an Array (by not calling to both versions of JsonConvert.DeserializeObject with the same input of the json string)
Explicit about how to introduce other properties
Handling the error case of unknown type of our propertyA (the one that can be either an array or an object).
Notice that instead of JsonConvert.DeserializeObject, I call JObject.Parse, and then ToObject<> for only the part I need in that particular case:
static ApiResult Deserialize(string json)
{
JObject j = JObject.Parse(json);
var propA = j["propertyA"];
switch (propA.Type.ToString())
{
case "Object":
return new ApiResult {
PropertyA = new[]{propA.ToObject<ApiItem>()},
SomethingElse = j["somethingElse"].ToObject<string>(),
};
case "Array":
return j.ToObject<ApiResult>();
default:
throw new Exception("Invalid json with propertyA of type " + propA.Type.ToString());
}
}
The API is pretty much the same, but I've added SomethingElse (for showing how other properties can be easily handled with this approach):
public class ApiResult
{
public ApiItem[] PropertyA { get; set; }
public string SomethingElse { get; set; }
}
public class ApiItem
{
public string First { get; set; }
public string Second { get; set; }
}
Working demo: https://dotnetfiddle.net/VLbTMu
JSON# has a very lightweight tool that allows you to achieve this. It will retrieve embedded JSON, regardless of whether or not the embedded JSON is an object, or array, from within larger JSON objects:
const string schoolMetadata = #"{ "school": {...";
var jsonParser = new JsonObjectParser();
using (var stream =
new MemoryStream(Encoding.UTF8.GetBytes(schoolMetadata))) {
Json.Parse(_jsonParser, stream, "teachers");
}
Here we retrieve a "teachers" object from within a larger "school" object.
best way to Serialize/Deserialize to/from JSON is Json.NET
Popular high-performance JSON framework for .NET
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
string json = JsonConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "Expiry": "2008-12-28T00:00:00",
// "Sizes": [
// "Small"
// ]
//}
string json = #"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys

Categories

Resources