Deserializing list of different objects - c#

Let's say, I have the the following C# classes
[JsonObject(MemberSerialization.OptIn)]
public class Parent
{
[JsonProperty]
public int SharedProp { get; set; }
}
public class ChildA : Parent
{
[JsonProperty]
public string ChildAProperty { get; set; }
}
public class ChildB : Parent
{
[JsonProperty]
public string ChildAProperty { get; set; }
}
Now I created a List<Parent> to which holds zero to n objects. Serialization of the list works fine and gives me a valid JSON file which I can deserialize. The problem is, I am currently only getting List<Parent> back and there is no ChildA or ChildB object.
I am using the Newtonsoft JSON serializer/deserializer. Is there any way to achieve this or do I have to split it into separate files/lists?

You need to specify the TypeNameHandling in the JsonSerializerSettings. Take a look at this article for an example.

Related

How to completely remove a property from an Object in c#

someone, please tell me the most straightforward syntax to remove a property from a c# object. I don't know why it is not clear on the internet.
{
"id": 1,
"name": "string",
"email": "string",
"cities": []
}
this is the response I get upon calling the get API. I want to remove the cities array, but I don't know why everything is so complicated in c#. I expect a magical short syntax like delete(in JS). Remember that this response is a dbContext response, not a standard object(DTO).
if you going to deserialize json, you can just create a class without cities property
public class Data
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
}
or if you can not change the class properties, just add an ignore attribute
using Newtonsoft.Json;
public class Data
{
.....
[JsonIgnore]
public List<object> cities {get; set;}
}
the code
Data data= JsonConvert.DeserializeObject<Data>(json);
if you want to remove only from json
var jsonParsed = JObject.Parse(json);
jsonParsed.Properties()
.Where(attr => attr.Name == "cities")
.First()
.Remove();
json=jsonParsed.ToString();
first, you can not change the class structure in runtime in C#.
you should define new object with your properties in mind, or use dynamic-expando objects to be able to manipulate object at runtime.
if your issue is only when you want to sterilize your object you can use [JsonIgnore] Property on the model:
public class MyDto
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
[JsonIgnore]
public string[] cities { get; set; }
}
this will tell you serializer to skip that property.
if you want to convert ur already define class to a dynamic object there are lots of ways.
you can use this nugget package that I wrote which have a DeSelect() method that returns a dynamic object without the specified properties:
https://www.nuget.org/packages/linqPlusPlus/1.3.0#readme-body-tab

System.Json - custom rules for property serialization skipping

I am trying to migrate from Newtonsoft.Json to System.Text.Json
However, I ran into a problem since I was using DefaultContractResolver.
My "custom" behaviour have these rules for property serialization:
Skip property serialization if it is marked with ReadOnly attribute
Skip property serialization in case of null (this is supported)
Skip property serialization which would serialize into an empty object
Example:
class Car
{
[ReadOnly]
public string Id { get; set; }
public string Name { get; set; }
public Person Owner { get; set; }
}
class Person
{
[ReadOnly]
public string Id { get; set; }
public string Name { get; set; }
}
Now, imagine, we have this data if no rules would apply.
{
"Id":"1234",
"Name":"Skoda",
"Owner":{
"Id":"abcd",
"Name":null
}
}
Now, if I serialize the object, I would like to get this instead.
{
"Name":"Skoda"
}
In order to ignore individual properties, you need to use the [JsonIgnore] attribute along with one of these conditions:
Always;
Never;
WhenWritingDefault;
WhenWritingNull.
You can also define a default ignore condition through the JsonSerializerOptions type.
If additional behavior is needed, you should write a custom converter.
Example:
class Person
{
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string Id { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
}
More information:
How to ignore properties with System.Text.Json
How to write custom converters for JSON serialization (marshalling) in .NET

C# class overwrite possibility

I am having a question, and probably it can not be done this way but maybe there is some other way i do not know, so I have a class that looks like this:
[DataContract]
public class Parent
{
[DataMember(Name="id")]
public int Id { get; set; }
[DataMember(Name = "value")]
public int Value { get; set; }
}
Now this class is a attribute value of different class:
[DataContract]
public class Location
{
[DataMember(Name="parent")]
public Parent Parent { get; set; }
}
But there is a catch, I need separate classes bout same type for example:
[DataContract]
public class Parent
{
[DataMember(Name="id")]
public int Id { get; set; }
}
[DataContract]
public class Parent
{
[DataMember(Name = "value")]
public int Value { get; set; }
}
Depending if Value is null or not (and I need this to be separate object cause as you see I want to map this). Is it possible to overwrite class so one class can have one or other attribute only?
You could solve it with inheritance, but IMHO it gets overdesigned.
Personally, I would all put into the Parent class. Make the properties nullable, than it's done. If you want to have some reliability that at least one property is set, you may want to make the setters private (given that you don't need to change them after creating the parent) and have factory methods to create parents with an Id or a Value.
Parent with encapsulation (if required):
[DataContract]
public class Parent
{
private Parent() {}
[DataMember(Name="id")]
public int? Id { get; private set; }
[DataMember(Name = "value")]
public int? Value { get; private set; }
public static Parent CreateWithId(int id)
{
return new Parent { Id = id };
}
public static Parent CreateWithValue(int value)
{
return new Parent { Value = value };
}
}
You can further add a ParentType property which returns an enum value which is either ParentType.ValueParent or ParentType.IdParent. Again, this is only useful when required, e.g. because it simplifies handling of parents, when there is a chance to get more different types or when you may want to support Id Parents with a null value as Id or the same with the Value.
Completely different solution is to store both Id and Value in the same property, since both are integers. Have another way to distinguish wether it is a Id or a Value.
[DataContract]
public class Parent
{
[DataMember(Name="id")]
public int Data { get; private set; }
[DataMember(Name="id")]
public ParentType ParentType { get; private set; }
public static Parent CreateWithId(int id)
{
return new Parent { Data = id, ParentType = ParentType.Id };
}
public static Parent CreateWithValue(int value)
{
return new Parent { Data = value, ParentType = ParentType.Value };
}
}
You're trying to represent DIFFERENT data by creating two different classes which are named the same. This is an error. Initially I wanted to suggest using interfaces or inheritance, but that makes no sense, as both Parent classes you wrote contain different things and there's no overlap.
If this case is directed purely because you need to map those properties to some data contract, then why not have a Parent class with both properties and just make those properties Nullable?
Something along the lines:
[DataContract]
public class Parent
{
[DataMember(Name="id")]
public int? Id { get; set; }
[DataMember(Name = "value")]
public int? Value { get; set; }
}
1 As said HimBromBree, you can put Parent classes in different namespaces.
WCF also allows you to provide different names for Serialization of classes through [DataContract] attribute :
[DataContract(Name="ParentA")]
public class Parent {
[DataMember(Name="id")]
public int Id { get; set; }
}
2 If your goal is to have Parent class to hold different values (Value or Id) depending on circumstances, you can also create two derived classes of Parent.
Let's call those classes ParentA and ParentB
Then on Parent, you should make a declaration for polymorphic serialization :
[DataContract]
[KnownType(typeof(ParentA))]
[KnownType(typeof(ParentB))]
public class Parent {}
[DataContract(Name="ParentA")]
public class ParentA : Parent {
[DataMember(Name="id")]
public int Id { get; set; }
}

Using Datacontract: WCF

How should i be declaring the datacontracts
My Operation contract has a Method:
Apple GetApples()
My data Contract Apple looks Like
[DataContract]
public class Apple
{
[DataMember]
public int Id { get; set; }
[DataMember]
public FruitType type { get; set; }
}
As there is another member of type FruitType.
[DataContract]
public class FruitType
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string type { get; set; }
}
OR
as a simple class
public class FruitType
{
public int Id { get; set; }
public string type { get; set; }
}
What is the difference between these two? other than that the simple type is not a datacontract and will depende on how i want to use it.?
how should i declare it??
Those attributes give you the control over how your properties will be represented in different formats. For example for XML you can specify the XML Namespace and XML node names.
Even if you are happy with default property names and default namespace, when you try to serialize data to XML, your XML nodes will have weird names such as typek_BackingField.
In other words, if you use WCF you should use DataContract and DataMember attributes, even if you think it works fine the formatted data may not look what you expect. As a result it removes compatibility with other (non-WCF) systems. Or even when you don't share your types (contracts) with other WCF systems.

How to deserialize XML attributes

I can create an object to hold a deserialized xml file. Mapping Xml elements to objects is easy, i just create properties in the in the class matching the name of the element. But how can i map Xml attributes to the class. For example, if i have this:
<Typestyle name="" location="" />
I want to deserialize the name and location attributes into properties on my class?
why not use the xsd.exe tool in the .NET framework SDK to create C# class code representing the schema. Then add those classes to your project and you can use XmlSerializer with those classes without needing to write the class code yourself.
Try this http://msdn.microsoft.com/en-us/library/x6c1kb0s.aspx
Look at XmlAttributeAttribute class.
public class TypeStyle
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("location")]
public string Location{ get; set; }
}
public class Typestyle
{
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string location { get; set; }
}

Categories