How to Serialise Dictionary<int, object> to JSON, but Ignore Key - c#

I have the following class property
public Dictionary<int, Hotel> Hotels { get; set; }
When I serialize to JSON the dictionary key is being serialized as follows:
{
"results": {
"id": "d875e165-4705-459e-8532-fca2ae811ae0",
"arrival_date": "2019-02-16",
"departure_date": "2019-02-17",
"expires": "2019-01-17T17:11:23.2941604+00:00",
"hotels": {
"9036": {
"hotel_id": 9036,
"name": "Beach View Hotel",
"address": null,
"star_rating": 0,
"review_score": 0,
"phone_number": null,
"website_url": null,
"email_address": null,
"channels": [
{
"id": 0,
"name": "Channel Name 0",
"offers": []
}
]
},
"9049": {
"hotel_id": 9049,
"name": "City House Hotel",
"address": null,
"star_rating": 0,
"review_score": 0,
"phone_number": null,
"website_url": null,
"email_address": null,
"channels": [
{
"id": 0,
"name": "Channel Name 0",
"offers": []
}
]
},
"9107": {
"hotel_id": 9107,
"name": "Park Hotel",
"address": null,
"star_rating": 0,
"review_score": 0,
"phone_number": null,
"website_url": null,
"email_address": null,
"channels": [
{
"id": 1,
"name": "Channel Name 1",
"offers": []
}
]
}
},
"errors": []
}
}
Is it possible to remove somehow, maybe by class property attribute?
"9036":
So the desired JSON becomes
"hotels": { "hotel_id": 9036, "name": "My Hotel Name",

The format "hotels": { "hotel_id": 9036, "name": "My Hotel Name", ... },.. is not valid, but you can make it an array "hotels": [ { "hotel_id": 9036, "name": "My Hotel Name", ... } ].
You can do so by marking your Dictionary with JsonIgnore and exposing a Collection of Hotels which contains Values from the Dictionary of Hotels.
For example,
var hotel = new Results
{
id= "d875e165-4705-459e-8532-fca2ae811ae0",
HotelDictionary = new Dictionary<int,Hotels> {
[2323]=new Hotels{Id=2323,Name="Sample1"},
[1323]=new Hotels{Id=1323,Name="Sample2"},
}
};
var jsonString = JsonConvert.SerializeObject(hotel,Newtonsoft.Json.Formatting.Indented);
Where Results and Hotels is defined as (please note i have ignored other properties to focus on dictionary, but you can add them in for your final solution).
public class Results
{
public string id { get; set; }
[JsonIgnore]
public Dictionary<int,Hotels> HotelDictionary { get; set; }
[JsonProperty("hotels")]
public IEnumerable<Hotels> Hotels => HotelDictionary.Select(x=>x.Value);
}
public class Hotels
{
[JsonProperty("hotel_id")]
public int Id{get;set;}
[JsonProperty("name")]
public string Name{get;set;}
}
Output
{
"id": "d875e165-4705-459e-8532-fca2ae811ae0",
"hotels": [
{
"hotel_id": 2323,
"name": "Sample1"
},
{
"hotel_id": 1323,
"name": "Sample2"
}
]
}

You cannot do that because this JSON structure is not valid:
"hotels": { "hotel_id": 9036, "name": "My Hotel Name", ... }, { ... }
You can, however, select only the values and serialize that:
hotels.Values;
To get this:
"hotels": [ { "hotel_id": 9036, "name": "My Hotel Name", ... }, { ... } ]
Given that that's part of a class, you'll need a new model:
public class SomeName
{
public List<Hotel> Hotels { get; set; }
}
var someName = new SomeName
{
Hotels = hotels.Values.ToList();
};

I think the problem may be that you need to add hotel_id as a property on the Hotel object.
Depending on where your data is coming from, this is probably a good idea anyways, not just in this case.

Related

Merge json objects that with the same value of property c#

How to combine JSON objects in the same response that has the same key and value. like if I've two objects that have the same language: Python I want to combine them and List the remaining data under this language Python I don't want it being repeated
[
[
{
"language": "Python",
"id": 319029846,
"full_Name": "beurtschipper/Depix",
"name": "Depix"
},
{
"language": "Python",
"id": 319169382,
"full_Name": "benwilber/boltstream",
"name": "boltstream"
},
{
"language": "Python",
"id": 316899719,
"full_Name": "r0ysue/r0capture",
"name": "r0capture"
}
],
[
{
"language": "YARA",
"id": 318029147,
"full_Name": "fireeye/red_team_tool_countermeasures",
"name": "red_team_tool_countermeasures"
}
],
[
{
"language": "TypeScript",
"id": 313443335,
"full_Name": "pmndrs/valtio",
"name": "valtio"
}
]
]
what the form I want is
[
[
{
"language": "Python",
"id": [319029846, 319169382, 316899719],
"full_Name": ["beurtschipper/Depix", "benwilber/boltstream", "r0ysue/r0capture"],
"name": ["Depix", "boltstream", "r0capture"]
}
],
[
{
"language": "YARA",
"id": 318029147,
"full_Name": "fireeye/red_team_tool_countermeasures",
"name": "red_team_tool_countermeasures"
}
],
[
{
"language": "TypeScript",
"id": 313443335,
"full_Name": "pmndrs/valtio",
"name": "valtio"
}
]
]
And this is the code i'm using
public class Items
{
[JsonPropertyName("language")]
public string Language { get; set; }
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("full_name")]
public string Full_Name { get; set; }
public string total_count { get; set; }
}
public class Root
{
[JsonPropertyName("items")]
public List<Items> Items { get; set; }
}
Root jObj2 = JsonConvert.DeserializeObject<Root>(readerResult);
var result = jObj2.Items.Select(x => new
{
x.Language,
x.Id,
x.Full_Name,
x.Name
}).GroupBy(x => x.Language).ToArray();
return new JsonResult(result);
GroupBy is a good place to start. Once you have the groups, you need to select the individual properties of each group into a new list:
var result = jObj2.Items
.GroupBy(x => x.Language)
.Select(group => new
{
Language = group.Key,
Ids = group.Select(x => x.Id).ToList(),
FullNames = group.Select(x => x.Full_Name).ToList(),
Names = group.Select(x => x.Name).ToList()
})
.ToArray();

Using ASP.NET Core 3, how do I make the json response not serialize a complex type?

I have this model:
public class Product
{
public Product()
{
this.Supplier = new Supplier();
}
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public int SupplierId { get; set; }
public ProductStatus Status { get; set; }
public Supplier Supplier { get; set; }
}
and another model:
public class Supplier
{
public Supplier()
{
this.Products = new List<Product>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public ICollection<Product> Products { get; set; }
}
Whenever I try to send json response using the product model, I get this kind of result:
{
"id": 1,
"name": "HP-ENVY 15",
"price": 800,
"supplierId": 0,
"status": 0,
"supplier": {
"id": 1,
"name": "HP",
"address": "Mckinley",
"products": []
}
}
And when trying to send a response using Supplier model:
{
"id": 1,
"name": "HP",
"address": "Mckinley",
"products": [
{
"id": 1,
"name": "HP-ENVY 15",
"price": 800,
"supplierId": 0,
"status": 0,
"supplier": {
"id": 0,
"name": null,
"address": null,
"products": []
}
},
{
"id": 12,
"name": "HP-PAVILION 14",
"price": 550,
"supplierId": 0,
"status": 0,
"supplier": {
"id": 0,
"name": null,
"address": null,
"products": []
}
},
{
"id": 13,
"name": "HP-ENVY 17",
"price": 1200.7,
"supplierId": 0,
"status": 0,
"supplier": {
"id": 0,
"name": null,
"address": null,
"products": []
}
},
{
"id": 14,
"name": "Printer xxx-2020",
"price": 300.5,
"supplierId": 0,
"status": 0,
"supplier": {
"id": 0,
"name": null,
"address": null,
"products": []
}
},
{
"id": 15,
"name": "Compaq Presario",
"price": 500.8,
"supplierId": 0,
"status": 0,
"supplier": {
"id": 0,
"name": null,
"address": null,
"products": []
}
}
]
}
Both responses tries to serialize the complext object inside them, is it possible to:
1.) When sending the json response for the Product model, It would only display Products and its Supplier only(the products property of that supplier would not be inlcluded)
2.) When sending the json response for the Supplier model, it would only display the Supplier and its products only(the supplier property for each product would not be inlcuded)
Are there json options that I need to configure on my middleware in order to achieve this? or should I create DTOs/classes where the Supplier complex object being referenced inside the Product model has no property of its product and vice-versa for the Supplier model(it has no products property).
Note: I'm aware that it's best to use viewmodel/dtos for json response, but in my example let's just say that both Product and Model are not domain classes but rather viewmodels, as my main problem is how do I prevent json from preventing serializing the object property.
JSON.net has the MaxDepth property for deserealizing up to a certain point.
Beware though that this will help you up to a point. It will not identify same object cyclic dependency, it will just stop at the second level of deserialization.
For the opposite thing (serialization) you can use json.net limit maxdepth when serializing to extend the JsonTextWriter

Deserialise Dynamic JSON string with Hierarchical data using JSON.NET

Ive a JSON like this
{
"id": 1,
"name": "user1",
"hasChildren": true,
"parentID": 0,
"children": [
{
"id": 2,
"name": "user2",
"paretnID": 1,
"hasChildren": true,
"children": [
{
"id": 3,
"name": "user3",
"parentID": 2,
"hasChildren": false,
"children": [
]
},
{
"id": 4,
"name": "user4",
"parentID": 2,
"hasChildren": false,
"children": [
]
}
]
},
{
"id": 5,
"name": "user5",
"paretnID": 1,
"hasChildren": true,
"children": [
{
"id": 6,
"name": "user6",
"parentID": 5,
"hasChildren": false,
"children": [
]
},
{
"id": 7,
"name": "user7",
"parentID": 5,
"hasChildren": false,
"children": [
]
}
]
},
{
"id": 8,
"name": "user8",
"paretnID": 1,
"hasChildren": true,
"children": [
{
"id": 9,
"name": "user9",
"parentID": 8,
"hasChildren": false,
"children": [
]
},
{
"id": 10,
"name": "user10",
"parentID": 8,
"hasChildren": true,
"children": [
{
"id": 11,
"name": "user11",
"parentID": 10,
"hasChildren": false,
"children": [
]
},
{
"id": 12,
"name": "user12",
"parentID": 10,
"hasChildren": false,
"children": [
]
}
]
}
]
}
]
}
Here as you can see its maintaining a hierarchy in each level in the children node. What my scenario is to convert this dynamic JSON as datatable rows
For deserilising this is how I tried
dynamic myJSON=jObject.parse(JSONstring);
but when I try myJSON.id its triggering an error like id not exists
What my plant is if children array has some elements, call another function to get its members and add to the datatable. But how can I get these fields from the dyanmic json string.
You can use like this
public class Child2
{
public int id { get; set; }
public string name { get; set; }
public int parentID { get; set; }
public bool hasChildren { get; set; }
public List<object> children { get; set; }
}
public class Child
{
public int id { get; set; }
public string name { get; set; }
public int paretnID { get; set; }
public bool hasChildren { get; set; }
public List<Child2> children { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public bool hasChildren { get; set; }
public int parentID { get; set; }
public List<Child> children { get; set; }
}
then Deserialize
var data=JsonConvert.DeserializeObject<RootObject>(JSONstring);
then you can access data.id
You need to add reference Newtonsoft.json

Deserialize JSON subdocument

I'm calling the JIRA Rest API to recieve a list of Worklog Objects.
The JSON I recieve looks like.
{
"startAt": 0,
"maxResults": 1,
"total": 1,
"worklogs": [
{
"self": "http://www.example.com/jira/rest/api/2/issue/10010/worklog/10000",
"author": {
"self": "http://www.example.com/jira/rest/api/2/user?username=fred",
"name": "fred",
"displayName": "Fred F. User",
"active": false
},
"updateAuthor": {
"self": "http://www.example.com/jira/rest/api/2/user?username=fred",
"name": "fred",
"displayName": "Fred F. User",
"active": false
},
"comment": "I did some work here.",
"visibility": {
"type": "group",
"value": "jira-developers"
},
"started": "2015-08-25T07:43:10.086+0000",
"timeSpent": "3h 20m",
"timeSpentSeconds": 12000,
"id": "100028"
}
]
}
As I said, I want to put it in a list.
var json = client.MakeRequest("", password, user);
List<Worklog> myList = JsonConvert.DeserializeObject<List<Worklog>>(json);
It doesn't work, because of
"startAt": 0,
"maxResults": 1,
"total": 1,
How can I make the deserializer ignore those properties?
Thanks for your help!
Either create a "RootObject" class that does contain the properties:
public class RootObject
{
public int startAt { get; set; }
public int maxResults { get; set; }
public int total { get; set; }
public List<Worklog> worklogs { get; set; }
}
And deserialize into that:
var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
// access rootObject.worklogs
Or step into the parsed JSON and deserialize from there:
JObject o = JObject.Parse(json);
JToken worklogsJson = o.SelectToken("worklogs");
var worklogs = worklogsJson.ToObject<List<Worklog>>();

Query JSON using LINQ

I have a Json response that I receive from an API call. It has several nested levels as show below (this is a snippet):
"Items": [
{
"Result": {
"Id": "191e24b8-887d-e111-96ec-000c29128cee",
"Name": "Name",
"StartDate": "2012-04-03T00:00:00+01:00",
"EndDate": null,
"Status": {
"Name": "Active",
"Value": 5
},
"Client": {
"Id": "35ea10da-b8d5-4ef8-bf23-c829ae90fe60",
"Name": "client Name",
"AdditionalItems": {}
},
"ServiceAgreement": {
"Id": "65216699-a409-44b0-8294-0e995eb05d9d",
"Name": "Name",
"AdditionalItems": {
"ScheduleBased": true,
"PayFrequency": {
"Id": "981acb72-8291-de11-98fa-005056c00008",
"Name": "Weekly",
"AdditionalItems": {}
},
"PayCycle": [
{
"Name": "Schedule Based",
"ScheduleBased": true,
"SelfBilling": false,
"Id": "a8a2ecc4-ff79-46da-a135-743b57808ec3",
"CreatedOn": "2011-09-16T23:32:19+01:00",
"CreatedBy": "System Administrator",
"ModifiedOn": "2011-09-16T23:32:19+01:00",
"ModifiedBy": "System Administrator",
"Archived": false
}
]
}
},
}
]
...
What I want to do is retreive the data from the PayCycle node using Linq. I can for example get the items with a value of true using Result.ServiceAgreement.AdditionalItems.SchedultedBased using the following Linq in the Controller:
var result = from p in data["Data"]["Items"].Children()
where (bool)p["Result"]["ServiceAgreement"]["AdditionalItems"]["ScheduleBased"] == true
select new
{
Name = (string)p["Result"]["Client"]["Name"],
Id = (string)p["Result"]["Client"]["Id"]
};
Now I need to get Result.ServiceAgreement.AdditionalItems.Paycycle.ScheduleBased and SelfBilling properties. How do I do this if PayCycle is also an array, how do I get the children as I did with Data.Items in the Linq above so that I can have the where clause filter on both these items?
You can deserialize the JSON into a dynamic object, and then use Linq to Objects:
[TestMethod]
public void TestMethod1()
{
const string json = #"""Items"": [
{
""Result"": {
""Id"": ""191e24b8-887d-e111-96ec-000c29128cee"",
""Name"": ""Name"",
""StartDate"": ""2012-04-03T00:00:00+01:00"",
""EndDate"": null,
""Status"": {
""Name"": ""Active"",
""Value"": 5
},
""Client"": {
""Id"": ""35ea10da-b8d5-4ef8-bf23-c829ae90fe60"",
""Name"": ""client Name"",
""AdditionalItems"": {}
},
""ServiceAgreement"": {
""Id"": ""65216699-a409-44b0-8294-0e995eb05d9d"",
""Name"": ""Name"",
""AdditionalItems"": {
""ScheduleBased"": true,
""PayFrequency"": {
""Id"": ""981acb72-8291-de11-98fa-005056c00008"",
""Name"": ""Weekly"",
""AdditionalItems"": {}
},
""PayCycle"": [
{
""Name"": ""Schedule Based"",
""ScheduleBased"": true,
""SelfBilling"": false,
""Id"": ""a8a2ecc4-ff79-46da-a135-743b57808ec3"",
""CreatedOn"": ""2011-09-16T23:32:19+01:00"",
""CreatedBy"": ""System Administrator"",
""ModifiedOn"": ""2011-09-16T23:32:19+01:00"",
""ModifiedBy"": ""System Administrator"",
""Archived"": false
}
]
}
}
}
}
]";
dynamic data = System.Web.Helpers.Json.Decode("{" + json + "}");
var result = from i in (IEnumerable<dynamic>)data.Items
where i.Result.ServiceAgreement.AdditionalItems.ScheduleBased == true
select new
{
i.Result.Client.Name,
i.Result.Client.Id
};
Assert.AreEqual(1, result.Count());
Assert.AreEqual("client Name", result.First().Name);
Assert.AreEqual("35ea10da-b8d5-4ef8-bf23-c829ae90fe60", result.First().Id);
}
Note that I had to add brackets { and } around your example json string, or else the .NET json parser doesn't like it.
To start off, I'm not familiar with writing LINQ/LAMBDA using this format ["some"]["thing"].
My first step would be to create some classes/objects to house the data in to ease creating any code afterwards.
e.g.
public class Result
{
public Guid Id { get; set; }
public string Name { get; set; },
public DateTime StartDate { get; set; }
//you get the idea
}
But possibly try the following?
var result = from p in data["Data"]["Items"].Children()
where (bool)p["Result"]["ServiceAgreement"]["AdditionalItems"]["ScheduleBased"] == true
&& (p["Result"]["ServiceAgreement"]["AdditionalItems"]["PayCycle"]).Where(o => o.["ScheduleBased"] == true)
select new
{
Name = (string)p["Result"]["Client"]["Name"],
Id = (string)p["Result"]["Client"]["Id"]
};

Categories

Resources