How to map JSON to an object with a different structure? [duplicate] - c#

This question already has answers here:
Can I specify a path in an attribute to map a property in my class to a child property in my JSON?
(7 answers)
Closed 6 years ago.
I have some JSON with this schema:
{
"person":{
"name":"test",
"family":"testi"
},
"Employee":{
"id":54,
"department":"web development",
"skils":[{"type":"C#", "grade":"good"},{{"type":"SQL", "grade":"Expert"}}]
}
}
and I need to map this JSON to following classes:
class Employee {
public int id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
public string Department { get; set; }
public Skill[] Skills { get; set;}
}
class skill {
public string Type { get; set; }
public string Grade { get; set; }
}
Now is there any way to map my JSON schema to my C# object?
I am using the Newtonsoft.Json library and am trying to use the JsonProperty attribute like this:
[JsonProperty("Person.Name")]
on my Employee class. But this does not work. Is there any way to solve this problem?

Your class is not proper for your json. You must equalize properties of class and properties of json object.
Your json has a property named person but your class does not have it.
MappedObject mappedObject = JsonConvert.DeserializeObject<MappedObject>(yourJson);
class MappedObject{
public Person person;
public Employee employee;
}
class Person{
public string name;
public string family;
}
class Employee {
public intid{get; set;}
public string deartment {get; set;}
public Skill[] skills {get; set;}
}
class skill{
public string type{get; set;}
public string grade{get; set;}
}
OR better way you can use dynamic object.
dynamic result = new ExpandoObject();
result = JsonConvert.DeserializeObject(yourJson);

Related

What is the System.Text.Json alternative to XmlElementAttribute("Emp", GetType(Employee))

I have a class as below with the property of type object. Earlier I used to assign class dynamically to object property Item as below using XmlElementAttribute.
[Serializable]
public class Employee
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
}
[Serializable]
public class Department
{
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
}
[Serializable]
public class ParentClass
{
public string Location { get; set; }
[System.Xml.Serialization.XmlElementAttribute("Emp", GetType(Employee)), System.Xml.Serialization.XmlElementAttribute("Dept", GetType(Department))]
public object Item { get; set; }
}
Here is XML data containing property Emp, then automatically Employee class get assigned to the Item property of ParentClass.
I want to have similar functionality with System.Text.Json.
Is there any alternative for XmlElementAttribute("Emp", GetType(Employee)) in json like below
[System.Text.Json.JsonPropertyName["Emp", GetType(Employee))]]
I have JSON input below
{
"Location": "Chicago",
"Emp": {
"EmployeeID":123,
"EmployeeName":"Peter"
}
}
Here since my JSON property name is Emp, I want to assign the Employee type dynamically to the object Item property of ParentClass.
{
"Location": "NJ",
"Dept": {
"DepartmentID":567,
"DepartmentName":"IT"
}
}
Similarly, if I have JSON data as above, I want to assign Department type to the object property Item of ParentClass.
Kindly suggest any solution for this.
When I googled, I'm able to find only below
[JsonPropertyName("Wind")]
But I want to bind type dynamically similar to XmlElementAttribute("Emp", GetType(Employee))

AutoMapper with nested objects and container class

I'm developing an API with .NET core and using AutoMapper.
all the API responses will be wrapped with a data element in the JSON response like below example
GET User
{
"data" {
"id" : 1,
"user_name": "abc"
"countryr" : {
"id" : 1348,
"code" : "USA"
}
}
}
So we have an entity for User and Country
public partial class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public virtual Country country { get; set; }
}
public partial class Country
{
public int Id { get; set; }
public string Code{ get; set; }
}
To map entities to DTO we have below reponseDTO
public class GetUserDTO {
public User data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public String user_name {get; set;}
public Country country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public String code {get; set;}
}
As per my understanding , I should map the entity User to the UserDTO and Country entity to CountryDTO but what about GetUserDTO class itself? it basically contains other entities so the class itself cannot be mapped to anything it acts like a container.
So below what I did so far which is not correct
public class UserProfile : AutoMapper.Profile
{
public MappingProfile()
{
CreateMap<User, GetUserDTO>();
CreateMap<User, UserDto>()
.ForMember(userDto => userDto.user_name, map => map.MapFrom(user => user.FirstName))
CreateMap<Country, CountryDto>();
}
}
Json response
{
"data" : null
}
What to do for such situations?
You should not refer your entity classes in your DTO classes. You might want to change the DTO as below.
public class GetUserDTO {
public UserDto data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public string user_name {get; set;}
public CountryDto country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public string code {get; set;}
}
And then in the Mapper profile, you need to explicitly map each property as cases are different(AutoMapper will map without explicity map if the names are exactly the same. In your example, there is a case difference)
And then remove the below line from the MapperProfile as there is no mapping from the User class to GetUserDTO class. This is the reason you are not getting any output.
CreateMap<User, GetUserDTO>();
While getting the data, you should create a new instance of GetUserDTO class and set the property "data" from the result of mappaing of the User object.
This will get you the output.

Deserialize Objects with JsonConvert Class

I have a weird issue and am confused.
I have 3 class:
public class ProductInfo
{
public List<PartInfo> PartInfos { get; set; }
public string Name { get; set; }
}
public class SubProductInfo : PartInfo
{
public ProductInfo ProductInfo { get; set; }
}
public class PartInfo
{
public string Name { get; set; }
public string Desc { get; set; }
}
I have some information for industrial products. each product has some part and some sub product. for each product I have an object from type 'ProductInfo'. for each part related to this product I have an object of type 'PartInfo' and for each sub product related to this product I have an object of type 'SubProductInfo'. this 'ProductInfo' object serialized with 'JsonConvert.SerializeObject' method.
Example for serialized information:
{"PartInfos":[{"Name":"Part1","Desc":"Part1's Desc"},{"ProductInfo":{"PartInfos":[{"Name":"SubProduct1's Part1","Desc":"SubProduct1's Part1 desc"},{"Name":"SubProduct1's Part2","Desc":"SubProduct1's Part2 desc"}],"Name":"SubProduct1"},"Name":"SubProduct1 Details","Desc":"SubProduct1's Desc"}],"Name":"Product1"}
now I want to deserialize these JSONs to orginal object. I used:
JsonConvert.DeserializeObject<ProductInfo>(serializedObject)
but in deserialization 'SubProductInfo' objects will deserialize to 'PartInfo' objects.
how I can deserialize these JSONs to Exactly orginal objects?
Check out this: https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm
When you're serializing, the protocol you're using usually has manners to solve problems like this, usually by type hinting. Basically your serialized product contains data that tells the deserializre which type to use when deserializing.
Like I commented, I really don't undestand what you are trying to achieve.
I think you want to make a list of SubProductInfo instead of PartInfo, as PartInfo is the base of SubProductInfo. Like this:
public class ProductInfo
{
public List<SubProductInfo> PartInfos { get; set; }
public string Name { get; set; }
}
public class SubProductInfo : PartInfo
{
public ProductInfo ProductInfo { get; set; }
}
public class PartInfo
{
public string Name { get; set; }
public string Desc { get; set; }
}
If a SubProductInfo is something different than a PartInfo and both need to be part of you ProductInfo class, you should keep seperate lists:
public class ProductInfo
{
public List<PartInfo> PartInfos { get; set; }
public List<SubProductInfo> SubProductInfos { get; set; }
public string Name { get; set; }
}
public class SubProductInfo : PartInfo
{
public ProductInfo ProductInfo { get; set; }
}
public class PartInfo
{
public string Name { get; set; }
public string Desc { get; set; }
}
Maybe you should avoid inheritence, it helps visualizing your data model.
Edit
The second option won't (de)serialize as SubProductInfo has a circular connection to ProductInfo. You can mark the ProductInfo property as not serializeble and fill it after reading it from json. Or just remove it, since the code that wants to use it should have access to the parent ProductInfo class.

Only return some fields in JSON

I have an API that returns some data of a class in JSON. Is there any way to return only some specific fields of a C# class in JSON?
For example:
class Person {
public int Id{ get; set; }
public string Name { get; set; }
public string Family { get; set; }
public string Gender { get; set; }
}
Person myPerson = new Person();
var Json = (new
{
Person = myPerson
});
return Request.CreateResponse(HttpStatusCode.OK, Json);
It returns ID, Name, Family, Gender. I need to return only the Name and Family. I thought I can create an object and add my specific fields in the class in that object and return object?
Use anonymous types?
return Request.CreateResponse(HttpStatusCode.OK, new {Name = person.Name; Family = person.Family});
You should consider applying the DRY principle.
The DRY principle is not "never write code twice", but rather that "every piece of knowledge must have a single, unambiguous, authoritative representation in the system".
What this means is that you have to build a model that has a meaningful name, contains properties that it actually has, and can be changed as needed later without having to figure out where else in the application it's used. I'm certain you could also find a name that would better represent this area of the application.
Should I create a different model with just the properties I need or
use the same model and have NULL values for the field I don't use? Or just create anonymous type and make this way harder in future?
I don't recommend using the same model for your case, from my understanding of it. It's going to make your life easier down the road if you build a model that has a meaningful name as I said before.
So what should we do? I have seen many people trying to use JsonIgnore in domain model but you should not get down that path. You should avoid using JsonIgnore in domain model. I will give an example for it.
For example:
class Person {
public int Id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
public string Gender { get; set; }
}
So you have this model and you want other models to inherit from it but like in your case you don't want to return Id and Gender, only Name and Family. So you go like this.
class Person {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Family { get; set; }
public virtual string Gender { get; set; }
}
public class PersonNameModel : Person {
[JsonIgnore]
public override int Id { get; set; }
[JsonIgnore]
public override string Gender{ get; set; }
}
If a class has many properties and you only want to serialize a small
subset of them then adding JsonIgnore to all the others will be
tedious and error prone. The way to tackle this scenario is to add the
DataContractAttribute to the class and DataMemberAttributes to the
properties to serialize. This is opt-in serialization, only the
properties you mark up with be serialized, compared to opt-out
serialization using JsonIgnoreAttribute.
But, you can do it with the help of JsonIgnore but this way does not support XML format. So, in case your application has to support XML format more (or only support XML), instead of using Json.Net, you should use [DataContract] which supports both JSON and XML.
Datacontract is a great solution. It gives me a clean REST API. At the same time when I save the data in a no-sql, the ignored properties are persisted despite the objects being stored as json.
[DataContract]
public class Person {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Family { get; set; }
public virtual string Gender { get; set; }
}
public class PersonNameModel : Person {
// included in JSON
[DataMember]
public override string Name { get; set; }
[DataMember]
public override string Family { get; set; }
// other inherited properties will be ignored
}
I will also mention another way of doing it as there are more (custom contact resolver, Web API convention ("ShouldSerialize")...)
Another way you can do it is to decorate your auto property with JsonProperty attribute in order to skip the serialization of that field if it is null.
Example:
class Person {
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public int? Id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Gender { get; set; }
}
Happy coding!

How to deserialize json string to a domain object?

I am trying to convert the following json into a domain object .
JSON:
[{"name":"McDonalds","deals":[{"desc":"Onion Rings free with Double Cheese burgers"}],"geometry":{"lat":13.073412,"lng":80.221393}},{"name":"JusSportz","deals":[{"desc":"20% off on Wilson Rackets"}],"geometry":{"lat":13.073231,"lng":80.221181}}]
Model:
[DataContract]
public class Deal
{
[DataMember(Name="name")]
public string Store { get; set; }
[DataMember(Name="deals")]
public Offer[] Offers {get; set;}
[DataMember(Name="geometry")]
public GeoCoordinate Location { get; set; }
}
[DataContract]
public class Offer
{
[DataMember]
public string deal;
}
I tried the DataContractJsonSerializer that is in the System.Runtime.Serialization.Json namespace and there is apparently no way to convert a string into an object. Are there any other libraries which allow me to get this done? Or is there a way to get this done using this library (by converting the Json string to some intermediate format.)?
Here's how I deserialize JSON back to my domain objects.
using (var reader = new MemoryStream(Encoding.Unicode.GetBytes("YourStringValue")))
{
var ser = new DataContractJsonSerializer(typeof(Deal));
return (Deal)ser.ReadObject(reader);
}
Is this what you were looking for?
Try to change a bit Model:
[DataContract]
public class Deal
{
[DataMember(Name="name")]
public string Store { get; set; }
[DataMember(Name="deals")]
public Offer[] Offers {get; set;}
[DataMember(Name="geometry")]
public GeoCoordinate Location { get; set; }
}
[DataContract]
public class Offer
{
[DataMember(Name="desc")]
public string deal { get; set; }
}

Categories

Resources