How to set null for looping value when serialize - c#

I could not find a title for my question.
I have class as below
class Employee
{
public string Name { get; set; }
public List<Employee> Subordinates { get; set; }
}
if i serialize this class object, it is look like as below
[
{
"Name": "first person",
"Subordinates": [
{
"Name": "second person",
"Subordinates": null
}
]
},
{
"Name": "second person",
"Subordinates": null
}
]
But i need it like this
[
{
"Name": "first person",
"Subordinates": null
},
{
"Name": "second person",
"Subordinates": null
}
]
How can i get this
I am not using only this class. I have many class like employee so i need one solution for my all classes.
I am using below code for one class. I know it's not a solution, but i didn't find any better solution
var employees = //sql query .ToList()
foreach(var item in employees){
item.Subordinates = null;
}
return Json(employess)

Depending on what serializer you are using, the solution differs.
Try adding [NonSerialized] [XmlIgnore] [ScriptIgnore] to the List property.

Related

Possible to set primary reference?

I've a problem...
I have a class which contains a list of customers and a list with orders and every order holds the customer as reference. If I serialize the object like this I get:
{
"Customers": [
{
"$id": "1",
"FirstName": "A",
"LastName": "B"
}
],
"Orders": [
{
"Owner": {
"$ref": "1"
},
"Desc": "Soup"
}
]
}
That's fine.. but if I remove the customer I get:
{
"Customers": [],
"Orders": [
{
"Owner": {
"$id": "1",
"FirstName": "A",
"LastName": "B"
},
"Desc": "Soup"
}
]
}
But what I wish to have is:
{
"Customers": [],
"Orders": [
{
"Owner": null,
"Desc": "Soup"
}
]
}
The code I used:
[JsonObject(IsReference = true)]
public class Customer
{
public String FirstName;
public String LastName;
}
public class Order
{
public Order(Customer T, String What)
{
Owner = T;
Desc = What;
}
public Customer Owner;
public String Desc;
}
public class Settings
{
public List<Customer> Customers = new List<Customer>();
public List<Order> Orders = new List<Order>();
}
public MainWindow()
{
InitializeComponent();
Settings Data = new Settings();
Customer Customer = new Customer() { FirstName = "A", LastName = "B" };
Data.Customers.Add(Customer);
Order PlaceOrder = new Order(Data.Customers.First(), "Soup");
Data.Orders.Add(PlaceOrder);
Console.WriteLine(JsonConvert.SerializeObject(Data, Formatting.Indented));
Data.Customers.Remove(Customer);
Console.WriteLine(JsonConvert.SerializeObject(Data, Formatting.Indented));
Close();
}
Can someone help me figure out how to do this?
Right now you are only removing the Customer from the list:
Data.Customers.Remove(Customer);
But the Customer still exists and is still referenced by the PlaceOrder. If you debug set a break point after the line above, you can see that Data.Orders[0].Owner still contains the Customer object.
If you don't want the order in the JSON string to point to a customer, then you should set that reference to null:
Data.Orders[0].Owner = null;
// or...
PlaceOrder.Owner = null;
That should result in your desired JSON output.

Deserialize JSON with Newtonsoft

I'm having problems with this JSON to use it in combobox and datagridview. I'm using Newtonsoft to do it:
{
"users": [
{
"id": 1,
"name": "Test 1",
"email": "test1#test.com",
"events": [
{
"id": 1,
"name": "Event 1",
"date": "11/10/2019",
"finish": 0
},
{
"id": 2,
"name": "Event 2",
"date": "12/10/2019",
"finish": 0
}
]
},
{
"id": 2,
"name": "Test 2",
"email": "test2#test.com",
"events": [
{
"id": 2,
"name": "Event 2",
"date": "17/10/2019",
"finish": 0
}
]
}
]
}
And this is the class (JsonEvent.cs). Generated with json2csharp.com:
using System;
using System.Collections.Generic;
namespace TestDO.Models
{
class JsonEvent
{
public partial class Admin
{
public List<User> Users { get; set; }
}
public partial class User
{
public long Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<Event> Events { get; set; }
}
public partial class Event
{
public long Id { get; set; }
public string Name { get; set; }
public string Date { get; set; }
public long Finish { get; set; }
}
}
}
But now, I do not know how to use the result with combobox datasource or a datagrid.
So far the only time I've worked with this has been for a much simpler topic like this (this is and example, It is not related to this):
JsonResponde.cs
namespace TestDO.Models
{
class JsonResponse
{
public string Upgraded { get; set; }
public string time{ get; set; }
}
}
And then I check the result of Upgraded like this:
var jResponse = JsonConvert.DeserializeObject<JsonResponse>(json);
if (jResponse.Upgraded == "true")
But I don't know how to do it with a more complex json.
I want to use event id for combobox and event name for display.
And for datagrid, user id, user name, event name, event date for each line.
Thank you in advance for any help to solve the problem.
Your C# representation of the JSON you provided seems to perfectly fine and matching. Therefor you should be able to do something like the following:
var jResponse = JsonConvert.DeserializeObject<Admin>(json);
If the JSON array Users is not nested in another object you could also convert it to a List<User> (HashSet or similar collections should also work), if it's the only property of your Admin class. This would look something like this:
var jResponse = JsonConvert.DeserializeObject<List<User>>(json);
For this to work your JSON would need to look something like this:
[
{
"id": 1,
"name": "Test 1",
"email": "test1#test.com",
"events": [
{
"id": 1,
"name": "Event 1",
"date": "11/10/2019",
"finish": 0
},
{
"id": 2,
"name": "Event 2",
"date": "12/10/2019",
"finish": 0
}
]
},
{
"id": 2,
"name": "Test 2",
"email": "test2#test.com",
"events": [
{
"id": 2,
"name": "Event 2",
"date": "17/10/2019",
"finish": 0
}
]
}
]
Edit
If you want to feed your users to a combo-box, you can just pass the list to the combo-box. See the example below:
ComboBox cb = new ComboBox();
cb.DataSource = jResponse.Users.SelectMany(x => x.Events.OrderBy(y => y.Id).Select(y => y.Name));
Of course your Users object contains a lot of information, that is just an assumption, that you want to have all the names of the users in the ComboBox.
You need to deserialize your json to an object of the Admin class you created, which you can do like this:
var AdminObj = JsonConvert.DeserializeObject<Admin>(json);
From there, you have access your Users list by AdminObj.Users, which you can loop through to get whatever data you need for your application.

Collection Navigation Properties returning odd JSON hierarchy

I have 2 classes:
public class A
{
public int Id { get; set; }
public string Name { get; set; }
public B myB { get; set; }
}
public class B
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<A> myAs { get; set; }
}
Im using Postman to test the Api calls.
public IEnumerable<B> GetBs()
{
return _context.Bs.Include(b => b.myAs).ToList();
}
returns as expected, B objects and a list of their associated A objects:
{
"Id": 1,
"Name": "B2",
"myAs": [
{
"Id": 1,
"Name": "A1"
},
{
"Id": 2,
"Name": "A2"
}
]
},
{
"Id": 2,
"Name": "B3",
"myAs": [
{
"Id": 3,
"Name": "A3"
},
{
"Id": 4,
"Name": "A4"
},
{
"Id": 5,
"Name": "A5"
}
]
}
The reverse however returns a wierd hierarchical structure:
public IEnumerable<A> GetAs()
{
return _context.As.Include(a => a.myB).ToList();
}
returns:
[
{
"Id": 1,
"Name": "A1",
"myB": {
"Id": 1,
"Name": "B2",
"myAs": [
{
"Id": 2,
"Name": "A2"
}
]
}
},
{
"Id": 2,
"Name": "A2",
"myB": {
"Id": 1,
"Name": "B2",
"myAs": [
{
"Id": 1,
"Name": "A1"
}
]
}
},
{
"Id": 3,
"Name": "A3",
"myB": {
"Id": 2,
"Name": "B3",
"myAs": [
{
"Id": 4,
"Name": "A4"
},
{
"Id": 5,
"Name": "A5"
}
]
}
}
]
The GetAs method returns A objects with B objects with further nested A objects.
My understanding after a little research (I could be very wrong here), is that because A has a navigation property to B (myB) and B has a navigation property to a list of A objects (myAs) this is causing some kind of loop.
My questions are
Is my understanding here correct ? Is this why the hierarchy is returning in this weird layout ?
How do i fix this ? I can take the ICollection navigation property out of the domain model but then I can no longer query As and their associated Bs ?
note A and B are not actually my domain models. I just wanted to keep the example as simple as possible.
Thanks in advance.
A few things here:
The output has the expected shape. As you suspect, the bidirectional references are being expanded by the serializer. Think of what would happen if you manually serialized each property of each object recursively. That is what happening.
To solve the immediate problem configure you default serializer settings like this:
jsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.Serialization.ReferenceLoopHandling.Ignore;
The above is useful when prototyping but when your application is more formalized, you should create and return dedicated view model types from your web API endpoints.
public class AViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class BViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<AViewModel> myAs { get; set; }
}
public IEnumerable<BViewModel> GetBs()
{
return _context.Bs.Include(b => b.myAs)
.Select(b => new BViewModel
{
Id = b.Id,
Name = b.Name,
As = b.As.Select(a => new AViewModel
{
Id = a.Id,
Name = a.Name
})
})
.ToList();
}
It is worth noting that there are libraries, such as the well regarded AutoMapper, that can perform these translations between model types for you, automatically assigning corresponding properties by name using reflection.
Personally, I try to avoid reflection based approaches as much as possible as they tend to render code difficult to reason about statically. This hinders both human readers such as ourselves and tools like the C# language.
That said, it can be worth the tradeoff depending on the task at hand. I hope to eventually see language level support that eliminates such boilerplate assignments without stepping into the realm of stringiness but I have a long time to wait.

Json formatting with Json.net in C#

I am trying to parse a bunch of XML files into a single JSON file, which is already working.
The final JSON file looks like the following:
{
"items": [
{
"subItems": [
{
"Name": "Name",
"Value": "Value",
"Type": "text"
},
{
"Name": "Name",
"Value": "Value",
"Type": "text"
}
]
},
{
"subItems": [
{
"Name": "Name",
"Value": "Value",
"Type": "text"
},
{
"Name": "Name",
"Value": "Value",
"Type": "text"
},
...
Instead, I want to achieve the following structure:
{
"items": [
[
{
"Name": "Name",
"Value": "Value",
"Type": "text"
},
{
"Name": "Name",
"Value": "Value",
"Type": "text"
}
],
[
{
"Name": "Name",
"Value": "Value",
"Type": "text"
},
{
"Name": "Name",
"Value": "Value",
"Type": "text"
}
]
]
}
But I don't know how to define my objects in order to do so, my current structure is as follows:
public class Items
{
public List<Item> items;
}
public class Item
{
public List<SubItem> subItems;
}
public class SubItem
{
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
}
How should I do this?
The answer is simple: turn your objects into lists: This will remove the prop names (and object notation in json).
public class Items
{
public List<Item> items; //list with prop name 'items'
}
public class Item : List<SubItem> // list in list like json notation
{
}
public class SubItem // Object in the list in list
{
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
}
As #FlilipCordas noted Inheriting from list is bad practice (for good reason)
you are better of this way:
public class Items
{
public List<List<SubItem>> items; //list with list with prop name 'items'
}
public class SubItem // Object in the list in list
{
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
}
Copy your json then go in Visual Studio.
Click on "Edit" > "Paste Special" > "Paste JSON as Classes"
All the classes are automatically created. I hope this tip could help you.

Deserialize nested JSON array in C#

I have a JSON array with nested objects, representing a menu, as this:
[
[
{
"name": "Item 1",
"id": 1
},
{
"name": "Item 2",
"id": 2,
"children": [
[
{
"name": "Item 21",
"id": 21
}
]
]
},
{
"name": "Item 3",
"id": 3,
"children": [
[
{
"name": "Item 31",
"id": 31,
"children": [
[
{
"name": "Item 311",
"id": 311
},
{
"name": "Item 312",
"id": 312
}
]
]
},
{
"name": "Item 32",
"id": 32
},
...
And I want to deserialize it using JavaScriptSerializer. I have some code as shown below but is not working.
var serializer = new JavaScriptSerializer();
var objects = serializer.Deserialize<Menu>(jsonData);
...
public class Menu
{
public int id { get; set; }
public string name { get; set; }
public Menu[] children { get; set; }
}
The error I get is "The type 'Menu' is not supported to deserialize a matrix".
I would appreciate any help on how to declare the custom object.
Cheers.
Your root object is a 2d jagged array of objects. The properties "children" are also 2d jagged arrays. Thus your Menu class needs to be:
public class Menu
{
public int id { get; set; }
public string name { get; set; }
public Menu [][] children { get; set; }
}
And deserialize your JSON as follows:
var serializer = new JavaScriptSerializer();
var objects = serializer.Deserialize<Menu [][]>(jsonData);
Alternatively, if you prefer lists to arrays, do:
public class Menu
{
public int id { get; set; }
public string name { get; set; }
public List<List<Menu>> children { get; set; }
}
And then
var objects = serializer.Deserialize<List<List<Menu>>>(jsonData);
Could the issue be that the actual data is an array but you're telling it to expect just one Menu?

Categories

Resources