Prevent class property from being serialized - c#

I added attribute serializable to class but, due to this, class property is getting serialized.
I used [XmlIgnore] to all property but still it is serializing the property
[Serializable]
public class Document
{
[DataMember]
[XmlIgnore]
public string FileURL { get; set; }
[DataMember]
[XmlIgnore]
public string FileSize { get; set; }
}
It's serialized like below tag-
<a:_x003C_DocumentDetails_x003E_k__BackingField>
<a:Document>
<a:_x003C_FileType_x003E_k__BackingField>PDF</a:_x003C_FileType_x003E_k__BackingField>
<a:_x003C_FileURL_x003E_k__BackingField>C:/log/Test.pdf</a:_x003C_FileURL_x003E_k__BackingField>
</a:Document>
</a:_x003C_DocumentDetails_x003E_k__BackingField>

If you are using the [Serializable] attribute, you need to use the [NonSerialized] attribute on any members (public or private) that you don't want serialised.
[DataMember] is used when the class is marked with the [DataContract] attribute and [XmlIgnore] is used when you are explicitly using the XmlSerialiser on a class.
[Serializable]
public class Document {
[NonSerialized]
public string FileURL { get; set; }
[NonSerialized]
public string FileSize { get; set; }
}

try [JsonIgnore] or [IgnoreDataMember] attribute, that will help you.

If you're using WCF with an "out of the box" configuration, you're probably using the DataContractSerializer to serialize messages, not the XmlSerializer.
In order to have members of your contract class not be serialized, you decorate them with the IgnoredDataMember attribute:
[Serializable]
public class Document
{
[DataMember]
public string FileURL { get; set; }
[IgnoredDataMember]
public string FileSize { get; set; }
}

Have you tried IgnoreDataMemberAttribute as per the docs?
https://msdn.microsoft.com/en-us/library/system.runtime.serialization.ignoredatamemberattribute.aspx

Related

Deserializing XML to C# child class

My XML :
<?xml version="1.0" encoding="UTF-8"?>
<response id="41cc788a-bc22-4ce0-8e1c-83bf49bbffed">
<message>Successfully processed the request</message>
<payload>Alive</payload>
</response>
My Classes :
[XmlRoot("response")]
[Serializable]
public abstract class ESBResponseBase<T>
{
[XmlAttribute]
public string Id { get; set; }
public string Message { get; set; }
public T Payload { get; set; }
}
[XmlRoot("response")]
[Serializable]
public class ESBResponseIsAlive : ESBResponseBase<string>
{
}
Note that if I don't have these classes on the child classes it throws an exception so it seems inheritance doesn't work with these.
My Serialization Code :
XmlSerializer serializer = new XmlSerializer(typeof (ESBResponseIsAlive));
var esbResponseIsAlive = (ESBResponseIsAlive) serializer.Deserialize(result);
However when I serialize my object properties are null.
I think more than likely this is an issue with inheritance in classes used for serializing. It is possible to simply change the base class to the actual concrete class and use the Generic, but I preferred to have it strongly typed.
As it turns out, XMLSerializer is case-sensitive. My class now looks like the following and it works.
[XmlAttribute("id")]
public string Id { get; set; }
[XmlElement("message")]
public string Message { get; set; }
[XmlElement("payload")]
public T Payload { get; set; }

Compatibility of Serializable and DataContract objects using DataContractSerializer

I have two classes, one inherits another - base class is DataContract, child is Serializable. I want to move property from child to base class, but after moving it I get exception saying that during deserializing the child class BackingProperty is not found. How can I correctly move that property to base class?
Do you have the base class decorated with the KnownType attribute?
[KnownType(typeof(SuperClass))]
[DataContract]
public class BaseClass
{
...
}
It's because serialization for Serializable marked classes and DataContract a bit different.
Here is a serializer I used for the samples:
var ser = new DataContractSerializer(typeof(BaseClass), new List<Type>() { typeof(ChildClass) });
You can compare:
[DataContract]
public class BaseClass
{
[DataMember]
public string Name { get; set; }
}
[Serializable]
public class ChildClass: BaseClass
{
public string SecondName { get; set; }
public int Age { get;set; }
}
Xml for that class (using DataContractSerializer, which is standard for WCF ):
<BaseClass i:type="ChildClass" xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>Ivan</Name>
<_x003C_Age_x003E_k__BackingField>1</_x003C_Age_x003E_k__BackingField>
<_x003C_SecondName_x003E_k__BackingField>Petrov</_x003C_SecondName_x003E_k__BackingField>
</BaseClass>
But when you move a property to base class, which is marked ad DataContract:
[DataContract]
public class BaseClass
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string SecondName { get; set; }
}
[Serializable]
public class ChildClass: BaseClass
{
public int Age { get;set; }
}
Here is xml for that case:
<BaseClass i:type="ChildClass" xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>Ivan</Name>
<SecondName>Petrov</SecondName>
<_x003C_Age_x003E_k__BackingField>1</_x003C_Age_x003E_k__BackingField>
</BaseClass> <BaseClass i:type="ChildClass" xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>Ivan</Name>
<SecondName>Petrov</SecondName>
<_x003C_Age_x003E_k__BackingField>1</_x003C_Age_x003E_k__BackingField>
</BaseClass>
As a result you have different element name in Xml (SecondName vs _x003C_SecondName_x003E_k__BackingField) and these two xml are really different.
It's better to use a common approach in you solution, to mark everything or Serializable or DataContract. I would recommend to use DataContract.
EDIT 1:
Of course you can try to make a trick with property naming:
[DataMember(Name = #"_x003C_SecondName_x003E_k__BackingField", IsRequired = true)]
public string SecondName { get; set; }
And XML will be quite the same in result. You can also try to expose feilds for Serializable objects instead of properties:
[Serializable]
public class ChildClass : BaseClass
{
public string SecondName;// { get; set; }
public int Age; //{get;set;}
}
And xml will be:
<BaseClass i:type="ChildClass" xmlns="http://schemas.datacontract.org/2004/07/Serialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>Ivan</Name>
<Age>1</Age>
<SecondName>Petrov</SecondName>
</BaseClass>
But, unfortunately, if you move your property from ChildClass to BaseClass the order of properties will be changed. But DataContractSerializer always enforces the order of elements during deserialization and as a result not all the fields will be deserialzed. But you can switch to use the XmlSerializer in your service, which supports unordered deserialization.
Finally: Marking all data contract with DataContract
Even if you mark both your classes with DataContract, DataMember:
[DataContract]
public class BaseClass
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string SecondName { get; set; }
}
[DataContract]
public class ChildClass : BaseClass
{
//[DataMember]
//public string SecondName { get; set; }
[DataMember]
public int Age {get;set;}
}
And then move a property from ChildClass to BaseClass, it will still not work. Your property will be null (or default value), as the order has been changed :(

ASP.net Web API: change class name when serializing

I have a Data Transfer Object class for a product
public class ProductDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
// Other properties
}
When the Asp.net serializes the object in JSON (using JSON.NET) or in XML, it generates ProductDTO objects.
However, i want to change the name during serialization, from ProductDTO to Product, using some kind of attributes:
[Name("Product")]
public class ProductDTO
{
[Name("ProductId")]
public Guid Id { get; set; }
public string Name { get; set; }
// Other properties
}
How can i do this?
I can't see why the class name should make it into the JSON-serialized data, but as regards XML you should be able to control the type name via DataContractAttribute, specifically via the Name property:
using System.Runtime.Serialization;
[DataContract(Name = "Product")]
public class ProductDTO
{
[DataMember(Name="ProductId")]
public Guid Id { get; set; }
[DataMember]
public string Name { get; set; }
// Other properties
}
DataContractAttribute is relevant because the default XML serializer with ASP.NET Web API is DataContractSerializer. DataContractSerializer is configured through DataContractAttribute applied to serialized classes and DataMemberAttribute applied to serialized class members.
An option is to use the default .Net Serialization attributes for this:
[DataContract(Name = "Product")]
public class ProductDTO
{
[DataMember(Name = "ProductId")]
public Guid Id { get; set; }
[DataMember]
public string Name { get; set; }
// Other properties
}

Deserializing JSON from ASP.net web service into C# object

After spending a day reading through posts here I still can't get this to work so hopefully this makes sense to someone here.
The web service returns this simple JSON
{"d":{"__type":"TestWebServices.Person","Name":"Bob","FavoriteColor":"Green","ID":0}}
Then I am using C# code to deserialize
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(Person));
Person someone = (Person)jsonSerializer.ReadObject(responseStream);
When I use this model someone is created but all the properties are null
[DataContract]
public class Person {
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}
I tried being more literal and used this model
[DataContract]
public class Person {
[DataMember]
public PersonItem d { get; set; }
}
[DataContract]
public class PersonItem {
[DataMember]
public string __Type { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}
And got this error, which I don't even know where to start with
Element ':d' contains data from a type that maps to the name ':GEMiniWebServices.Person'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'TestWebServices.Person' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.
Any thoughts?
Thanks
__Type should never be part of your object. It's a hint to the serializer. Also, the type hint that you have in your JSON object is bad. Stand-Alone JSON Serialization says:
To preserve type identity, when serializing complex types to JSON a
"type hint" can be added, and the deserializer recognizes the hint and
acts appropriately. The "type hint" is a JSON key/value pair with the
key name of "__type" (two underscores followed by the word "type").
The value is a JSON string of the form
"DataContractName:DataContractNamespace" (anything up to the first
colon is the name).
The type hint is very similar to the xsi:type attribute defined by the
XML Schema Instance standard and used when serializing/deserializing
XML.
Data members called "__type" are forbidden due to potential conflict
with the type hint.
It works with the following if you rewrite the __type declaration as Person:#TestWebServices or eliminate it:
namespace TestWebServices
{
[KnownType(typeof(Person))]
[DataContract]
public class PersonWrapper
{
[DataMember]
public Person d { get; set; }
}
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}
}
Try adding (and I'm kind of taking a bit of a stab here so the exact namespace my be incorrect)
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/TestWebServices.Person")]
to your DataContractAttribute on Person.
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/TestWebServices.Person")]
public class Person {
[DataMember]
public PersonItem d { get; set; }
}
[DataContract]
public class PersonItem {
[DataMember]
public string __Type { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string FavoriteColor { get; set; }
[DataMember]
public int ID { get; set; }
}

XmlSerializer and different field in class and xml attribute

I have xml with several items, for example:
<TestObject>
<TestElement1/>
<TestElement2/>
</TestObject>
<TestObject>
<TestElement1/>
<TestElement2/>
</TestObject>
Also I have class:
class TestClass {
public int TestElement1 { get; set; }
public int Element { get; set; }
}
If I do:
XmlSerializer s = new XmlSerializer(typeof(List<TestClass>));
List<TestClass> list = (List<TestClass>)s.Deserialize("myXml.xml");
After it I get list with objects TestClass, but property Element didn't set. How I must change serialization, if I want to set TestElement2 in Element field?
You need to decorate the Element property with an [XmlElement] attribute:
[XmlRoot("TestObject")]
class TestClass {
public int TestElement1 { get; set; }
[XmlElement("TestElement2")]
public int Element { get; set; }
}
Try XmlElement attribute
public class TaxRates{
[XmlElement(ElementName = "TaxRate")]
public decimal ReturnTaxRate;
}
see Controlling XML Serialization Using Attributes

Categories