I have a ForumController where I have a function ChangeOrder with a ChangeOrderDto. Here is the code:
[HttpPost("change-order")]
public async Task<ActionResult> ChangeOrder([FromBody] ChangeOrderDto[] forums)
{
foreach (var dto in forums)
{
var forum = await context.Forums.FindAsync(dto.Id);
if (forum is not null)
{
forum.Order = dto.Order;
forum.ParentId = dto.ParentId;
}
}
await context.SaveChangesAsync();
return Ok();
}
public class ChangeOrderDto
{
public int Id { get; set; }
public int Order { get; set; }
public int ParentId { get; set; }
}
However when I post to /api/forum/change-order with json
{
"forums": [
{id: 3, order: 1, parent_id: 1},
{id: 4, order: 2, parent_id: 1}
]
}
I get this error in response:
Validation failed, forums field is required.
I tried adding [FromBody("forums")] but it did not work.
If I understand your requirement correctly, your JSON should look like this:
[
{"id": 3, "order": 1, "parent_id": 1},
{"id": 4, "order": 2, "parent_id": 1}
]
You may need to change "parent_id" to "parentId" as well since you don't specify any custom property name for the JSON parser.
It then would look like this (also formatted for legibility):
[
{
"id": 3,
"order": 1,
"parentId": 1
},
{
"id": 4,
"order": 2,
"parentId": 1
}
]
If you want to validate your JSON, you can also use a service like this one: https://jsonformatter.curiousconcept.com/
Extrapolating on the answers from below your post (Jon Skeet and ewerspej), lets build this payload:
First, You want to send an array of data:
[
]
This array have in your case 2 objects:
[
{
},
{
}
]
Objects you transferring have some properties with values:
[
{
"id": 3,
"order": 1,
"parentId": 1
},
{
"id": 4,
"order": 2,
"parentId": 1
}
]
Take a look especially at the name of parrentId property - I think this should be named like this in the payload instead of parent_id that You used in your payload.
Related
I am building a web app using Blazor WASM with a .NET backend. We are hitting a problem, where the json returned from the API is bigger than we want/need it to be. Maybe the right solution is to write custom serializer methods for each action on the controllers, but was hoping there was a simpler way of reducing the size of the serialized json without having to do that.
Consider the following classes:
public class Comment
{
[Key]
public int CommentID { get; set; }
public int FilterSelectionGroupID { get; set; }
[InverseProperty("Comments")]
public virtual FilterSelectionGroup FilterSelectionGroup { get; set; }
[Required(ErrorMessage = "The comment should not be empty.")]
public string Comment { get; set; }
}
public class FilterSelectionGroup
{
[Key]
public int FilterSelectionGroupID { get; set; }
[ForeignKey("FilterSelectionGroupID")]
public virtual ICollection<Comment> Comments { get; set; }
[ForeignKey("FilterSelectionGroupID")]
public virtual ICollection<FilterSelectionGroupValueAssigment> FilterSelectionGroupValueAssigments { get; set; }
}
I get them from the database using EFCore and then return the data from the controller:
[HttpGet]
public async Task<IActionResult> Get([FromQuery] PaginationFilter pagination)
{
var validPagination = new PaginationFilter(pagination.PageNumber, pagination.PageSize);
var items = await _powerBICommentService.Get(validPagination);
return Ok(new PagedResponse<Comment>(items.Data, validPagination.PageNumber, validPagination.PageSize, items.TotalRecords));
}
Finally the resulting json is something like this. Note that the comments get repeated in the FilterSelectionGroup (it doesn't cause a loop because I have set o.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles on Startup.cs).
This gets even worse, because in the real model, there are other classes that have references to the comments, so I can have the comments repeating 3 or 4 times in the final structure.
What I'd like would be of a way to say if class Comment has been serialized on "level 1" then don't serialized it again.
"data": [
{
"CommentID": 1,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": {
"FilterSelectionGroupID": 1,
"Comments": [
null,
{
"CommentID": 2,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": null
},
{
"CommentID": 3,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": null
}]
}
},
{
"CommentID": 2,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": {
"FilterSelectionGroupID": 1,
"Comments": [
{
"CommentID": 1,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": null
},
null,
{
"CommentID": 3,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": null
}]
}
},
{
"CommentID": 3,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": {
"FilterSelectionGroupID": 1,
"Comments": [
{
"CommentID": 1,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": null
},
{
"CommentID": 2,
"FilterSelectionGroupID": 1,
"FilterSelectionGroup": null
},
null
]
}
}
]
Thanks for any help/suggestions.
I am attempting to deserialize a tree of JSon objects I get back into a DTO. The tree can be up to 4 levels deep, and over 1200 nodes. The code is C# using Newtonsoft.Json for deserialization.
EDIT
The JSon looks like:
[
{
"id": 1095,
"name": "Item1-1",
"children": [
{
"id": 1097,
"name": "Item2-2",
"children": [
{
"id": 18,
"name": "Item3-3",
"children": [
{
"id": 19,
"name": "Item4-4",
"children": [],
"level": 4,
"parentId": 18
},
{
"id": 20,
"name": "Item5-4",
"children": [],
"level": 4,
"parentId": 18
}
],
"level": 3,
"parentId": 1097
}
],
"level": 2,
"parentId": 1095
}
],
"level": 1,
"parentId": null
}
]
My DTO is similar to this:
public class MyDTO
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("children")]
public MyDTO[] Children { get; set; }
[JsonProperty("level")]
public int Level { get; set; }
[JsonProperty("parentId")]
public int ParentId { get; set; }
public MyDTO()
{
}
}
I like Brian Rogers' solution in this link, which deserializes the json into objects:
How do I use JSON.NET to deserialize into nested/recursive Dictionary and List?
public static class JsonHelper
{
public static object Deserialize(string json)
{
return ToObject(JToken.Parse(json));
}
private static object ToObject(JToken token)
{
switch (token.Type)
{
case JTokenType.Object:
return token.Children<JProperty>()
.ToDictionary(prop => prop.Name,
prop => ToObject(prop.Value));
case JTokenType.Array:
return token.Select(ToObject).ToList();
default:
return ((JValue)token).Value;
}
}
}
I call the JSonHelper with object obj = JsonHelper.Deserialize(jsonString);
I have been experimenting with converting this code into a method to convert to MyDTO, but I keep running into compiler errors. I have attempted to simply convert the JValue casts with MyDTO and move on to the List with a List.
My goal is to call MyDTO obj = JsonHelp.Deserialize(jsonString) and get the tree of MyDTO objects back. Is it possible to do what I am trying, or should I find a way to cast each object to MyDTO?
First your JSON is missing a brakcet ], then your model needs a nullable parentId. Making a couple simple changes you can then you JsonConvert.DeserializeObject<IEnumerable<MyDTO>>(json).
So your JSON should look like this:
[
{
"id": 1095,
"name": "Item1-1",
"children": [
{
"id": 1097,
"name": "Item2-2",
"children": [
{
"id": 18,
"name": "Item3-3",
"children": [
{
"id": 19,
"name": "Item4-4",
"children": [],
"level": 4,
"parentId": 18
},
{
"id": 20,
"name": "Item5-4",
"children": [],
"level": 4,
"parentId": 18
}
],
"level": 2,
"parentId": 1095
}],
}],
"level": 1,
"parentId": null
}
]
And can be deserialized with this model:
public class MyDTO
{
public int Id { get; set; }
public string Name { get; set; }
public MyDTO[] Children { get; set; }
public int Level { get; set; }
public int? ParentId { get; set; }
}
Using this code:
var dto = JsonConvert.DeserializeObject<IEnumerable<MyDTO>>(json);
Please i am new to C# and entity framework, I am working on a projects using web api. I also use postman to test my data and validate them before inserting to database.
My controller Create will accept a json shown below. The JSON object is mapped to my person model, Assets element of the json is a collection from asset model. what i want to do is retrieve all the asset name in the json and check whether they exist in the asset table. if they exist, get the IDs of the asset and save them all to "PersonAsset" table.
NOTE that "PersonAsset" contains "PersonID" & "AssetId"
I have spent over 24 hours trying to solve this problem, i need help please
{
"Id": 0,
"FirstName": "stringFine",
"MiddleName": "test-Sesan",
"LastName": "stringOkay",
"Gender": "Male",
"DateOfBirth": "10-10-2017",
"BirthCertificate": 0,
"Asset": 0,
"WorkTypeId": 2,
"DwellingId": 2,
"HouseholdRoleId": 2,
"HealthFacility": 1,
"Relationship": "string",
"Education": 0,
"MaritalStatusId": 2,
"MobileNumber": "080099813501",
"SettlementTypeId": 2,
"CommunityId": 3,
"SocialGroup": 0,
"Address": "string",
"IsInSchool": 0,
"ReferenceNumber": "100/NSIO/NSR/345660",
"DateInterviewed": "10-10-2017",
"IsActive": true,
"Assets": [
{
"Name": "Testing"
}
],
"SocialGroups": [
{
"Name": "string"
}
]
}
[ResponseType(typeof(PersonModel))]
[ModelValidator]
[HttpPost]
public IHttpActionResult Create(PersonModel model)
{
try
{
var person = Factory.Persons.Create(model);
Service.Persons.Insert(person);
person = Service.Persons.Get(person.Id);
var dto = Factory.Persons.Create(person);
return CreatedAtRoute("DefaultApi", new { id = dto.Id },dto);
}
catch(dbexception){}
How do i accept the values in below JSON and use it in my controller endpoint
"Assets": [
{
"Name": "Testing"
}
],
What does your PersonModel look like? See if the code below helps.
Create Asset model
public class Asset
{
public string Name { get; set; }
}
and then in PersonModel
public class PersonModel
{
public List<Asset> Assets { get; set; }
}
I'm trying to iterate through nested JSON arrays using C# and JSON.NET. The JSON represents categories for an online webstore - below is an example. My goal is to create a list of all of the names of categories.
{
"id": 2,
"parent_id": 1,
"name": "Main Category List",
"is_active": true,
"position": 1,
"level": 1,
"product_count": 0,
"children_data": [
{
"id": 9,
"parent_id": 2,
"name": "Mens Clothing",
"is_active": true,
"position": 6,
"level": 2,
"product_count": 0,
"children_data": []
},
{
"id": 8,
"parent_id": 2,
"name": "Womens Clothing",
"is_active": true,
"position": 7,
"level": 2,
"product_count": 0,
"children_data": [
{
"id": 223,
"parent_id": 8,
"name": "Outdoor Clothing",
"is_active": true,
"position": 1,
"level": 3,
"product_count": 0,
"children_data": []
},
{
"id": 224,
"parent_id": 8,
"name": "Hiking Clothing",
"is_active": true,
"position": 2,
"level": 3,
"product_count": 0,
"children_data": []
},
{
"id": 596,
"parent_id": 8,
"name": "Dresses",
"is_active": true,
"position": 3,
"level": 3,
"product_count": 0,
"children_data": [
{
"id": 694,
"parent_id": 596,
"name": "Summer Dresses",
"is_active": true,
"position": 13,
"level": 4,
"product_count": 0,
"children_data": [
{
"id": 720,
"parent_id": 694,
"name": "Accessories",
"is_active": true,
"position": 1,
"level": 5,
"product_count": 0,
"children_data": [ ]
}
]
}
]
}
]
},
{
"id": 10,
"parent_id": 2,
"name": "Sale & Clearance",
"is_active": true,
"position": 8,
"level": 2,
"product_count": 0,
"children_data": []
}
]
}
There could be varying levels of categories and I need to parse every one. I want to get every category and create a map. For example (Main Category List --> Women's Clothing --> Outdoor Clothing). I'm thinking I can check the depth of children data but I don't know how to keep checking deeper and deeper into the next Json object.
JObject responseObject = JObject.Parse(response.Content);
foreach (JObject category in getCatResponseObj.SelectToken("children_data"))
{
while loop checking depth of children_data
}
Were it me, I would create the most complete JSON file I can come up with (including all possible entries), then use json2csharp or an equivalent tool to create c# classes then deserialize the Json and work with it natively. You may have to massage the results a bit - but I think you can get there. If that didn't work, I would use Newtonsofts JSON LINQ Features (documentation). JToken gives you parent / children combinations that allows you to traverse up and down the tree. The samples in the documentation are really good, so no need of my filling up the page with duplicate info.
(Generated from your example)
public class ChildrenData
{
public int id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public bool is_active { get; set; }
public int position { get; set; }
public int level { get; set; }
public int product_count { get; set; }
public List<object> children_data { get; set; }
}
public class RootObject
{
public int id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public bool is_active { get; set; }
public int position { get; set; }
public int level { get; set; }
public int product_count { get; set; }
public List<ChildrenData> children_data { get; set; }
}
This appears to be a recursively defined structure. You should create a function to extract the values of each of the children so you could reuse it recursively.
IEnumerable<string> GetCategoryNames(JObject data)
{
yield return (string)data["name"];
foreach (var name in data["children_data"].Cast<JObject>().SelectMany(GetCategoryNames))
yield return name;
}
Then call it on the root object to get your names putting in a list or whatever.
var obj = JObject.Parse(response.Content);
var names = GetCategoryNames(obj).ToList();
Otherwise, if you want to indiscriminately get all names in the object tree, just keep in mind that SelectToken()/SelectTokens() also takes json path queries. So to get all names of all descendants, you'd just do this:
let names = obj.SelectTokens("..name").ToList();
C# | .NET 4.5 | Entity Framework 5
I have data coming back from a SQL Query in the form of ID,ParentID,Name. I'd like to take that data and parse it into a Hierarchical JSON string. So far it seems to be much more of a daunting task than it should be. Since I'm using Entity the data comes back nicely to me as an IEnumerable. Now I believe I just need some form of recursion, but I'm not quite sure where to start. Any help is appreciated.
Data Returns as
id parentId name
1 1 TopLoc
2 1 Loc1
3 1 Loc2
4 2 Loc1A
Code is
public static string GetJsonLocationHierarchy(long locationID)
{
using (EntitiesSettings context = new EntitiesSettings())
{
// IEnumerable of ID,ParentID,Name
context.GetLocationHierarchy(locationID);
}
}
The end result I'd hope would be something like this:
{
"id": "1",
"parentId": "1",
"name": "TopLoc",
"children": [
{
"id": "2",
"parentId": "1",
"name": "Loc1",
"children": [
{
"id": "4",
"parentId": "2",
"name": "Loc1A",
"children": [
{}
]
}
]
},
{
"id": "3",
"parentId": "1",
"name": "Loc2",
"children": [
{}
]
}
]
}
One way to turn a flat table into a hierarchy is to put all your nodes into a dictionary. Then iterate over the dictionary, and for each node, look up its parent and add it to the parent's children. From there, you just need to find the root and serialize it.
Here is an example program to demonstrate the approach:
class Program
{
static void Main(string[] args)
{
IEnumerable<Location> locations = new List<Location>
{
new Location { Id = 1, ParentId = 1, Name = "TopLoc" },
new Location { Id = 2, ParentId = 1, Name = "Loc1" },
new Location { Id = 3, ParentId = 1, Name = "Loc2" },
new Location { Id = 4, ParentId = 2, Name = "Loc1A" },
};
Dictionary<int, Location> dict = locations.ToDictionary(loc => loc.Id);
foreach (Location loc in dict.Values)
{
if (loc.ParentId != loc.Id)
{
Location parent = dict[loc.ParentId];
parent.Children.Add(loc);
}
}
Location root = dict.Values.First(loc => loc.ParentId == loc.Id);
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(root, settings);
Console.WriteLine(json);
}
}
class Location
{
public Location()
{
Children = new List<Location>();
}
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
public List<Location> Children { get; set; }
}
Here is the output:
{
"id": 1,
"parentId": 1,
"name": "TopLoc",
"children": [
{
"id": 2,
"parentId": 1,
"name": "Loc1",
"children": [
{
"id": 4,
"parentId": 2,
"name": "Loc1A",
"children": []
}
]
},
{
"id": 3,
"parentId": 1,
"name": "Loc2",
"children": []
}
]
}