How to Validate Duplicate Key values in JSON request - c#

{
"number": 1165,
"lineItems": [{
"itemId": 1,
"dynamicfields": {
"styleId": "V-Neck",
"style": "T-SHIRTS",
"cost": 30
}
},
{
"itemId": 2,
"dynamicfields": {
"styleId": "V-Neck",
"style": "T-SHIRTS",
"cost": 30
}
}]
}
How can I validate dynamic fields for two different item id is same? I need to show validation message saying duplicate dynamic fields should not allow.
I have done some RND but there I am finding for JSON Keys duplication but I need Key Values duplication check.

Here is a demo to check json data.
Models:
public class ModelB{
public int number { get; set; }
public List<LineItem> lineItems { get; set; }
}
public class LineItem
{
public int itemId { get; set; }
public Dynamicfields dynamicfields { get; set; }
}
public class Dynamicfields {
public string styleId { get; set; }
public string style { get; set; }
public int cost { get; set; }
}
Action:
public string CheckRepeat([FromBody]ModelB modelB)
{
for (int i = 0; i < modelB.lineItems.Count() - 1; i++)
{
if (modelB.lineItems.Where(l => JsonConvert.SerializeObject(l.dynamicfields) == JsonConvert.SerializeObject(modelB.lineItems[i].dynamicfields)).Count() > 1)
{
return "duplicate dynamic fields should not allow";
}
}
return "";
}
result:
If you get jsondata,you can convert it to ModelB with:
ModelB modelB=JsonConvert.DeserializeObject<ModelB>(jsondata);

Related

Parse (Deserialize) JSON with dynamic keys (C#)

I want to parse the JSON on the bottom. Till now I always have the static key for the variables, but in this example, the keys are always changing. Here the "58e7a898dae4c" and "591ab00722c9f" could have any value and change constantly. How can I get the value of the elements of the set to be able to reach the PreviewName value?
{
"key": "gun",
"objects": [
{
"name": "AK47",
"sets": {
"58e7a898dae4c": {
"set_id": "58e75660719a9f513d807c3a",
"preview": {
"resource": {
"preview_name": "preview.040914"
}
}
},
"591ab00722c9f": {
"set_id": "58eba618719a9fa36f881403",
"preview": {
"resource": {
"preview_name": "preview.81a54c"
}
}
}
}
}
]
}
public class Object
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("sets")]
public Dictionary<string, Set> Sets { get; set; }
}
public class Set
{
[JsonProperty("set_id")]
public string SetId { get; set; }
[JsonProperty("preview")]
public Preview Preview { get; set; }
}
public class Preview
{
[JsonProperty("resource")]
public ResourcePreview Resource { get; set; }
}
public class ResourcePreview
{
[JsonProperty("preview_name")]
public string PreviewName { get; set; }
}
var root = JsonConvert.DeserializeObject<RootObject>(json);
string previewName1 = root.Objects[0].Sets["58e7a898dae4c"].Preview.Resource.PreviewName;
string previewName2 = root.Objects[0].Sets["591ab00722c9f"].Preview.Resource.PreviewName;
you don't need to deserialize, you can parse
var jsonParsed=JObject.Parse(json);
string[] previewNames= ((JArray)jsonParsed["objects"])
.Select(v => ((JObject)v["sets"]))
.Select(i=>i.Properties().Select(y=> y.Value["preview"]["resource"])).First()
.Select(i=> (string) ((JObject)i)["preview_name"]).ToArray();
result
preview.040914
preview.81a54c

Flattening JSON-file c# - reduce number of foreach-loops

I'm trying to deserialize a nested json-file that looks like the following sample:
The output i want is "flat" table. I'm using .net 4.0 and I do not have the option of using third-party librabies like json.net.
{
"responsetime": 33,
"products": {
"totalProducts": 25,
"products": [
{
"id": 1,
"name": "Bike One",
"colors": [
{
"colorId": 44,
"name": "green",
"chemicals": [
{
"chemicalId": 99,
"chemicalName": "abc"
},
{
"chemicalId": 45,
"chemicalName": "bcd"
}
]
},
{
"colorId": 42,
"name": "blue",
"chemicals": [
{
"chemicalId": 96,
"chemicalName": "def"
},
{
"chemicalId": 22,
"chemicalName": "lkj"
}
]
}
]
}
]
}
}
From this I have genereated the following classes:
public class ResponseObject
{
public int responsetime { get; set; }
public Products products { get; set; }
}
public class Products
{
public int totalProducts { get; set; }
public Product[] products { get; set; }
}
public class Product
{
public int id { get; set; }
public string name { get; set; }
public Color[] colors { get; set; }
}
public class Color
{
public int colorId { get; set; }
public string name { get; set; }
public Chemical[] chemicals { get; set; }
}
public class Chemical
{
public int chemicalId { get; set; }
public string chemicalName { get; set; }
}
The output i want is a flat structure like the following:
1 Bike One 44 green 99 abc
1 Bike One 44 green 45 bcd
1 Bike One 42 blue 96 def
1 Bike One 42 blue 22 lkj
I am able to obtain this with the following code, however this implies 3 foreach-loops which i'm afraid will give bad performance if there are i.e. 100.000 products with N colors and N chemicals each.
Is there any other way to flatten this that will perform better using "vanilla" .net?
String jsonFileContent = File.ReadAllText(#"C:\example.json");
JavaScriptSerializer js = new JavaScriptSerializer();
js.MaxJsonLength = Int32.MaxValue;
ResponseObject rspns = js.Deserialize<ResponseObject>(jsonFileContent);
foreach (var product in rspns.products.products)
{
foreach (var color in product.colors)
{
foreach (var chemical in color.chemicals)
{
Console.WriteLine(product.id);
Console.WriteLine(product.name);
Console.WriteLine(color.colorId);
Console.WriteLine(color.name);
Console.WriteLine(chemical.chemicalId);
Console.WriteLine(chemical.chemicalName);
}
}
}
You want to start having the ToString done by the same objects:
public class Products
{
public int totalProducts { get; set; }
public Product[] products { get; set; }
public override string ToString(){
// this iterates all products and stacks their string representation
var productsStrings = products.Select(x => x.ToString());
return productsStrings.Aggregate("", (a, n) => a + n + "\n").trimEnd();
}
}
public class Product
{
public int id { get; set; }
public string name { get; set; }
public Color[] colors { get; set; }
public override string ToString(){
// this gets all color strings and prepends the product string
// "1 Bike" + product (repeated CO times)
var colorSubstrings = colors.Select(x => x.GetSubstrings());
var appendOnStrings = colorSubstrings.Select(x => $"{id} {name} {x}");
return appendOnStrings.Aggregate("", (a, n) => a + n + "\n").trimEnd();
}
}
public class Color
{
public int colorId { get; set; }
public string name { get; set; }
public Chemical[] chemicals { get; set; }
public string[] GetSubstrings(){
// this gets all chemicals strings and prepends the color string
// "44 green" + chemicalString (repeated CH times)
return chemicals.Aggregate("", (a, chemical) => a + $"{colorId} {name} {chemical.ToString()} \n").trimEnd();
}
}
public class Chemical
{
public int chemicalId { get; set; }
public string chemicalName { get; set; }
public override string ToString(){
// this produces a string like -> "99 abc"
return $"{chemicalId} {chemicalName}";
}
}
Then you just parse the whole chain and call it:
String jsonFileContent = File.ReadAllText(#"C:\example.json");
JavaScriptSerializer js = new JavaScriptSerializer();
js.MaxJsonLength = Int32.MaxValue;
// deserializing JSON to rspns
ResponseObject rspns = js.Deserialize<ResponseObject>(jsonFileContent);
// result will contain the table with all products, colors and chemicals
var result = rspns.products.ToString();
// printing only once will surely improve the performances
Console.WriteLine(result);

Deserialise JSON iin C# using system.text.json with complex property name

I am trying to deserialise JSON files that have been created by a third party tool.
The files contain a property that can look like the below:
"RECIPE": [{
"ctPoint_0": {
"endTemperature": 25,
"hours": 0.07999999821186066,
"startTemperature": 25
},
"ctPoint_1": {
"endTemperature": 30,
"hours": 0.07999999821186066,
"startTemperature": 25
},
"ctPoint_2": {
"endTemperature": 25,
"hours": 0.07999999821186066,
"startTemperature": 30
},
"pointCount": 3,
"type": "CyclicTemp"
}, {
"cycles": 2,
"type": "Repeat"
}, {
"cycles": 1,
"duration": {
"days": 0,
"hours": 0
},
}]
I am using system.text.json to deserialise:
newProgram = JsonSerializer.Deserialize<Program>(jsonString, options);
Extract of my Program class:
public class Program
{
public IList<Recipe> RECIPE { get; set; }
}
Recipe and cyclic_data struct:
public struct Cyclic_Data
{
public float endTemperature { get; set; }
public float hours { get; set; }
public float startTemperature { get; set; }
}
public struct Recipe
{
public int cycles { get; set; }
// Would like to use this
public IList<Cyclic_Data> ctPoints { get; set; }
// this deserialises ok but obviously only to hardcoded limit
public Cyclic_Data ctPoint_0 { get; set; }
public Cyclic_Data ctPoint_1 { get; set; }
public Cyclic_Data ctPoint_2 { get; set; }
public Cyclic_Data ctPoint_3 { get; set; }
public Cyclic_Data ctPoint_4 { get; set; }
public Cyclic_Data ctPoint_5 { get; set; }
public Cyclic_Data ctPoint_6 { get; set; }
public Cyclic_Data ctPoint_7 { get; set; }
public Cyclic_Data ctPoint_8 { get; set; }
public Cyclic_Data ctPoint_9 { get; set; }
public Cyclic_Data ctPoint_10 { get; set; }
public Duration duration { get; set;}
public string type { get; set; }
public float temperature { get; set; }
public int pointCount { get; set; }
}
As per the comments, if I have a number of discrete variables of type Cyclic_Data e.g. ctPoint_0 then this successfully deserialises, however as this list could theoretically be arbitrarily large it would be a nonsense to try to declare all possible property names.
I would really like to use an IList to read in all ctPoint_X values but am struggling to find a way to do so. I was looking at the newton soft implementation instead and wondering whether [JsonProperty("name")] could be used with RegEx to solve this but could not find any successful example done in this way.
How can I deserialise this in a sensible manner?
EDIT:
I am currently looking at a custom JsonNamingPolicy to rename any property name matching a RegEx "^ctPoint_[0-9]+$" to ctPoints, will let you know if this succeeds, please comment if this is doomed to fail or if there is a better way..
EDIT 2:
I tried the method outlined above but it didn't work as the correct JSON for a list of items doesn't have the name at beginning of each item, however this started me thinking about the problem differently. What I ended up doing was some simple string replacements before the deserialisation. This worked fine :)
int location;
location = newText.IndexOf("\"ctPoint_0\":");
newText = newText.Replace("\"ctPoint_0\":", "\"ctPoints\": [");
if (location > 0)
{ int lastloc;
for (int i = 1; i < 999999; i++)
{
string nextString = "\"ctPoint_" + i.ToString() + "\": ";
lastloc = location;
location = newText.IndexOf(nextString);
newText = newText.Replace(nextString, "");
if (location == -1)
{
location = newText.IndexOf("}", lastloc);
newText = newText.Insert(location+1, "]");
break;
}
}
}
Thanks
You can try Dictionary<string, object> and check the object type during runtime
Here are the models required for this scenario
public class CtPoint
{
public int endTemperature { get; set; }
public double hours { get; set; }
public int startTemperature { get; set; }
}
public class Duration
{
public int days { get; set; }
public int hours { get; set; }
}
Here is the sample code to Deserialize the JSON using System.Text.Json.JsonSerializer
var results = System.Text.Json.JsonSerializer.Deserialize<List<Dictionary<string,object>>>(json);
foreach (var model in results)
{
foreach(var item in model)
{
if (item.Key.Contains("ctPoint"))
{
var ctPoint = System.Text.Json.JsonSerializer.Deserialize<CtPoint>(item.Value.ToString());
Console.WriteLine($"{item.Key}- {ctPoint.hours} {ctPoint.startTemperature} {ctPoint.endTemperature}");
}
else if (item.Key.Contains("duration"))
{
var duration = System.Text.Json.JsonSerializer.Deserialize<Duration>(item.Value.ToString());
Console.WriteLine($"{item.Key}- {duration.days} {duration.hours}");
}
else
{
Console.WriteLine($"{item.Key}- {item.Value.ToString()}");
}
}
}
Output
ctPoint_0- 0,0799999982118607 25 25
ctPoint_1- 0,0799999982118607 25 30
ctPoint_2- 0,0799999982118607 30 25
pointCount- 3
type- CyclicTemp
cycles- 2
type- Repeat
cycles- 1
duration- 0 0

How can I serialize a specific item from a list to JSON?

How can I serialize a specific item in a list to JSON?
I have the JSON content below from which I need to create a new JSON with only product 2.
So I deserialize the JSON and then try to re-serialize it and create the new JSON content.
JSON content 1:
{
"custId": 123,
"ordId": 4567,
"items":[
{
"prodId":77,
"price"":70,
"title":"Product 1"
},
{
"prodId":78,
"price"":95.99,
"title":"Product 2"
}
]
}
Deserialized class from above JSON:
class Item
{
public int prodId { get; set; }
public double price { get; set; }
public string title { get; set; }
}
class Summary
{
public int custId { get; set; }
public int ordId { get; set; }
public List<Item> items { get; set; }
}
How do I serialize the class with item[1] from the list?
New JSON content I need to create:
{
"custId": 123,
"ordId": 4567,
"items":[
{
"prodId":78,
"price"":95.99,
"title":"Product 2"
}
]
}
I have no idea how your code looks so here are a lot of assumptions.
Say you can deserialize/re-serialize the JSON object without further impediments. Between the two moments (deserialization and re-serialization) invoke the Filter() method I added below to the Summary class. This will remove all items but the one you want to keep.
class Summary
{
public int custId { get; set; }
public int ordId { get; set; }
public List<Item> items { get; set; }
public void Filter(int id)
{
int i;
i = 0;
while (i < items.Count)
{
if (items[i].prodId == id)
{
i++;
}
else
{
items.RemoveAt(i);
}
}
}
}
To be clear about the usage of this method:
// deserialize
summary.Filter(id); // id is the ID of the item to keep
// re-serialize to JSON as you already do
I hope this makes any sense to you.

How to retrieve following json string to separate objects in c#

hotel_pricesURL = string_builder.ToString();
RootobjectOne robjectOne = JsonConvert.DeserializeObject<RootobjectOne>(hotel_pricesURL);
List<OneStar> one_star_list = new List<OneStar>();
var check = robjectOne.onestar;
foreach(var items in check)
{
}
Including RootobjectOne class:
public class RootobjectOne
{
[JsonProperty("OneStar")]
public OneStar onestar { get; set; }
[JsonProperty("TwoStar")]
public TwoStar twostar { get; set; }
[JsonProperty("ThreeStar")]
public ThreeStar threestar { get; set; }
[JsonProperty("FourStar")]
public FourStar fourstar { get; set; }
[JsonProperty("FiveStar")]
public FiveStar fivestar { get; set; }
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
}
public class OneStar
{
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
[JsonProperty("median")]
public string median { get; set; }
[JsonProperty("lowest")]
public string lowest { get; set; }
[JsonProperty("value")]
public string value { get; set; }
//public string
}
**this is the response from the web service**
{
"5 star": {
"median": "134.04",
"lowest": "83.57",
"value": "134.04"
},
"1 star": {
"median": "28.86",
"lowest": "28.86",
"value": "28.86"
},
"4 star": {
"median": "76.35",
"lowest": "36.71",
"value": "76.35"
},
"2 star": {
"median": "24.78",
"lowest": "20.42",
"value": "24.78"
},
"3 star": {
"median": "37.65",
"lowest": "20.33",
"value": "37.65"
}
}
I am getting an error stating
Unable to cast object of type 'OneStar' to type'System.Collections.IEnumerator'
Why? And how do I solve this?
First, your class is implementing, but not inheriting the IEnumerable interface, so it is still not seen as a collection.
Second, even if you inherit it, you have no collections in OneStar and nothing to enumerate.
Third, all those Json flags are not necessary as you are just redefining the defaults that are already set.
Solution
You need an additional "wrapper" class that is your collection, or just omit your custom implementation of an enumerable collection (as it does not appear from your code that you need it) and just define the property that contains the class as a collection:
public class RootobjectOne
{
public List<OneStar> onestar { get; set; }
public List<TwoStar> twostar { get; set; }
public List<ThreeStar> threestar { get; set; }
public List<FourStar> fourstar { get; set; }
public List<FiveStar> fivestar { get; set; }
}

Categories