C# XmlSerializer: Deserializing child element text value - c#

I am having trouble deserializing my XML data into the data structures I've defined. I don't have any control over the creation of the XML, but it is structured like:
<order id="123456">
<userid>555</userid>
<merchant id="111">SomeMerchant</merchant>
</order>
I get the top level attributes and simple element values okay, but the part that is giving me issues is assigning the value of a child element to a property in a child class. My data structures look something like:
public class OrderData
{
[XmlElement("merchant", typeof(OrderMerchant))]
public OrderMerchant Merchant { get; set; }
[XmlAttribute("id")]
public int OrderID { get; set; }
}
[Serializable]
public class OrderMerchant
{
[XmlElement("merchant")]
public string Name { get; set; }
[XmlAttribute("id")]
public int ID { get; set; }
}
My problem: When I deserialize the XML and get an object, I have a Merchant object with an ID of 111 but a null Name. How do I mark up my object so that the element text is assigned to the Name attribute? I tried using the element name and I've tried an XPath expression (but I don't even know if that's allowed in this context).

You're telling the serializer to serialize an element merchant, and then the merchant object expects to receive another element "merchant" that will contain the name. Instead, mark the Name property with the attribute [XmlText] like so:
[Serializable]
public class OrderMerchant
{
[XmlText]
public string Name { get; set; }
[XmlAttribute("id")]
public int ID { get; set; }
}
And that should do it
Source

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

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 deal with changing element names when de-serializing JSON to C#

This is a follow on from Dealing with fanart.tv webservice response JSON and C#
So for artists you get a response where the main element is named the same as the artist (hence you call the webservice for thumbs for Metallica the root it called Metallica, you call it for Megadeth is is called Megadeth)
The previous question resolves that but the next stage down is albums which ends up containing two levels of these dynamically named elements so searching for a particular album and you get
{"Metallica":{"mbid_id":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab","albums":{"f44f4f73-a714-31a1-a4b8-bfcaaf311f50":{"albumcover":[{"id":"51252","url":"http://assets.fanart.tv/fanart/music/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab/albumcover/kill-em-all-504c485914b25.jpg","likes":"2"}]}}}}
So you have the same top level artist details with the dynamic name but now you have for albums you have an element which is named after the MusicbrainzID and then the collection of thumbs.
For the artist details I defined classes
public class ArtistThumbs
{
public string Name { get; set; }
[JsonProperty("mbid_id")]
public string MusicBrainzID { get; set; }
[JsonProperty("artistthumb")]
public List<Thumb> Thumbs { get; set; }
}
and
public class Thumb
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("likes")]
public string Likes { get; set; }
}
Then I can just de-serialize the artist to JSON with
var artistthumbs = JsonConvert.DeserializeObject<Dictionary<string, Artist>>(json);
question is how can I do the same for these albums? I really need to try and stick with JsonConvert.DeserializeObject if possible and really want to de-serialize to classes but I can't figure out how to model the classes
Same idea as the other question. Whenever you have dynamically changing property names for a JSON object you need to use a Dictionary. You can extend your existing classes easily enough to handle this.
First, define another class to hold the list of cover thumbs for the album:
class Album
{
[JsonProperty("albumcover")]
public List<Thumb> CoverThumbs { get; set; }
}
Then add the following to your property to your ArtistThumbs class:
[JsonProperty("albums")]
public Dictionary<string, Album> Albums { get; set; }
Then you can deserialize exactly as you have been doing:
var artistthumbs = JsonConvert.DeserializeObject<Dictionary<string, ArtistThumbs>>(json);
The Albums property now has the albums, where each key in the dictionary is the "MusicbrainzID" for the album and each value is the corresponding Album info.

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