XML Serialization of public property backing private field in C# - c#

I'm hoping someone can help answer this for me, as I've been pulling my hair out all morning trying to track down a solution to this issue.
I have a class that needs to be serialized to XML. The XML Serialization works as long as I'm serializing a simple public property. However, if I have a public property that acts as a getter for a private field that backs it, the public property isn't serialized (despite being decorated with [XmlAttribute()]). I've combed through MSDN and StackOverflow looking for answers, but to no avail. I've mocked up an example below.
[Serializable()]
[XmlRoot("foobar")]
public class FooBar
{
[XmlAttribute("foo")]
public string Foo { get; set; }
private bool bar;
[XmlAttribute("bar")]
public string Bar
{
get { return ConvertBoolToYesNo(bar); }
}
public FooBar()
{
Foo = "foo";
bar = true;
}
public string ConvertBoolToYesNo(bool boolToConvert)
{
if(boolToConvert == true)
return "yes";
else
return "no";
}
}
This returns <?xml version="1.0" encoding="us-ascii"?><foobar foo="foo" /> when I would expect it to return <?xml version="1.0" encoding="us-ascii"?><foobar foo="foo" bar="yes" />. Any suggestions would be appreciated.
Thanks in advance!

Check this answer right here:
Why are properties without a setter not serialized
Seems like it is a serializer limitation (by design) when you have "readonly" properties, try adding a "setter" and it might work.

I believe that read-only properties could not be seriazlied by XMLSerializer.

Related

Add XmlAttribute to C# Class for serialization

I'm having a bit of a head scratching moment here, as I think I'm doing this correctly!
I need to create an xml file as below, (I've left out the namespace declarations)
<races>
<race racename="race one">
<horse>
<name>Silver</name>
<age>6</name>
</horse>
</race>
</races>
Class races is a collection of class race, and class race is a collection of class horse. Below is the relevant code for race class which I have and is causing the problem (I think at least).
[Serializable]
[XmlType("race")]
public class Race : CollectionBase
{
private string _raceName;
[XmlAttribute("racename")]
public string RaceName
{
get
{
return this._raceName;
}
set
{
this._raceName = value;
}
}
I have the xml file building as expected EXCEPT the attribute racename is not being serialized. It is definitely being assigned to the race object before serialization. Any thoughts? I'm obviously missing something somewhere but I'm not sure how I'd even test where it's failing. Any help would be greatly appreciated!
Eoin.
In classes that implement IEnumerable, only collections are serialized, not public properties.
Use the Horse collection inside the Race class and remove :CollectionBase
[Serializable]
[XmlType("race")]
public class Race
{
[XmlElement("horse")]
public List<Horse> Horses { get; set; }
[XmlAttribute("racename")]
public string RaceName
{
get;
set;
}
public Race()
{
Horses = new List<Horse>();
}
}
Result
<race xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" racename="race one">
<horse>
<Name>Silver</Name>
<Age>6</Age>
</horse>
</race>
I suggest you to create a test console application in the solution and test code like this http://pastebin.com/bP340WmR if it works fine create a collections of objects and try to serialize. Doing it step by step will help to understand where exactly the problem is.

Deserialization an xml element that could be different types

I need to deserialize the flowing xml in c#
<Show>
<status>Canceled</status>
</Show>
<Show>
<status>2</status>
</Show>
my class is
[XmlRoot("Show")]`
public class Show
{
[XmlElement(ElementName = "status")]
public object status { get; set; }
}
and it works but i would like to deserialize it into an enum where in this example cancel is equal 2
public enum ShowStatus
{
[XmlEnum("Canceled")]
Canceled = 2
}
is there any way to do that without parse the public object status { get; set; } string value to enum
If you want to Deserialize the Enum using the name or the integer you can decorate the Enum with XmlEnum attribute and supply the integer.
This will deserialise "Canceled" and "2" as your Enum.
Example:
[XmlRoot("Show")]
public class Show
{
[XmlElement(ElementName = "status")]
public ShowStatus status { get; set; }
}
public enum ShowStatus
{
[XmlEnum("2")]
Canceled = 2
}
Test xml:
<?xml version="1.0"?>
<ArrayOfShow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Show>
<status>Canceled</status>
</Show>
<Show>
<status>2</status>
</Show>
</ArrayOfShow>
you cannot use object directly, XmlSerializer simply refuses to work with generics. Objects still have an underlying type, and when its de-serialzied, you have no idea what that type is. I made a workaround for it here but its not very pretty, or very useful.
You can custom implement IXmlSerializable, but that is a headache and a half.
I am assuming that the source of the problem is that you are taking this in as input from another source, and the field could be either integer or text, which you want to store as an enumerable. You are probably better of de-serializing it into a string, then simply parsing it later, afterwards. That would probably be the easiest way to do it. Everything else I can find is either about deserializing only the string values, or only the integer values, I have no idea if either of them can handle both forms of data, but it seems unlikely.
This Function will probably help you out a lot when it comes to that, it looks like it can handle the string or the numerical value, but I dont think XmlSerializer can use it. You would be better off with a string "dummy" that can save back to the Enum property using the Parse function. see this stackoverflow question for an example of the dummy property.
Example
Generally speaking it would look something like this:
[XmlRoot("Show")]`
public class Show
{
[XmlIgnore()]
public ShowStatus status { get; set; }
[XmlElement(ElementName = "status")]
public string StatusString
{
get { return status.ToString(); }
set { status = Enum.Parse(ShowStatus, value); }
}
}

C# Xml Deserialize plus design suggestions

In my project I need to build a generic deserializer that should be backward compatible.
Example: The XML looks like
<PolicyDef name = "sample" type="type1">
<Options ......>
</PolicyDef>
The "type" is enum - PolicyTypes
e.g
public Enum PolicyTypes
{
type1 = 0,
type2 = 1
}
The PolicyDef class is defined as
[XmlRoot("PolicyDef")]
public class PolicyDef
{
private string policyName;
private PolicyTypes policyType;
public PolicyDefinition()
{
}
[XmlAttribute]
public string Name
{
get
{
return this.policyName;
}
set
{
this.policyName = value;
}
}
[XmlAttribute]
public PolicyTypes Type
{
get
{
return this.policyType;
}
set
{
this.policyType = value;
}
}
}
The Problem with this approach is that if later on I put any type other than type 1 or type 2, the XMLDeserializer will throw exception.
so if i have the xml like
<PolicyDef name = "sample" type="type_new">
<Options ......>
</PolicyDef>
The deserializer will throw error as type_new not valid.
I was wondering if there is a way to hook into the deserializer process to catch that and set a default value rather than throw error. Say if there is any invalid value, then I would set that to "type1"
Or am open to suggestions regarding how to handle this problem
Thanks and Regards
This is possibly a duplicate of C# XML Deserialization W/ Default Values
Unfortunately it seems there is no way to fall back on default enum values during deserialisation. It will require slightly more work, but if you follow the linked example and implement IXmlSerializable in your PolicyDef class, you'll be able to implement the ReadXml method in a similar way (reflecting each of the properties using a try/catch block in order to check for a default value).
Hope that helps!
Thanks Chris for the suggestion, but I don't want end up writing the complete parsing code which could be messy if the XML and corresponding class is huge and complex. I anyway used a different approach.
I changed all the enum fields to string. In this case there would be no parsing error and then expose another property that would return the parsed value as enum and if the parsing fails, then return default enum value. E.g
private string policyName;
[XmlAttribute("Type")]
public string Type
{
private get
{
return this.policyType;
}
set
{
this.policyType = value;
try
{
this.PolicyType = (PolicyTypes)Enum.Parse(typeof(PolicyTypes), this.policyType);
}
catch(Exception)
{
this.PolicyType = PolicyTypes.DefaultPolicy;
}
}
}
public PolicyTypes PolicyType
{
get;
private set;
}
And use the class property to access the value rather than the xml attribute field.

WCF private member reference in DataContract class becomes NULL

I have a pecular problem in my WCF in the web services layer.
When I instantiate a private member (_Wagon) of my class (This instantiation is not null) in WCF, after few seconds, it's become null.
I've been trying to diagnose the problem, but no result so far.
So I'm turning to you people to help me solve this problem.
Thank you.
Hence there is my code :
[DataContract]
public class RemoteWagon
{
private readonly IWagon _Wagon;
public RemoteWagon(IWagon Wagon)
{
_Wagon = Wagon; //_Wagon isn't null here
}
~RemoteWagon()
{
Trace.WriteLine("Do nothing");
}
[DataMember]
public RemoteBreakpoint Breakpoint
{
set
{
if (value == null)
{
_Wagon.Breakpoint = null; //_Wagon member is NULL...
}
else
{
//... useless code in this context.
}
}
}
}
This would happen if your class had been serialized and deserialized by DataContractSerializer (for example when sending data between client and server)
Some reference: DataContractSerializer doesn't call my constructor?
If this is the case, then one possible solution, that worked for me: https://stackoverflow.com/a/9419943/724944
So a quick check&fix for this problem (I assume that you want to initialize the field yourself and not serialize it) would be to create method:
[OnDeserializing]
private void OnDeserializing(StreamingContext c)
{
_Wagon = initializeWagon();
}
however, as you probably noticed, you won't be able to pass Wagon during deserialization - you'll have to initialize it differently.
On the other hand, If you want _Wagon serialized, then expose it as public [DataMember] property
It seems that if you want _Wagon serialized you should mark it as a DataMember and ditch the "readonly" on it. If you don't want it serialized, show us your code to construct and fill this object.

XML serialisation won't write out lazy-evaluated property

Following on from a previous question, I am having trouble combining the Lazy<T> generic that was suggested with my XML Serialization.
Here is the functionality I am using for Lazy<T>:
public struct Lazy<T> where T : class, new()
{
private T _Value;
public bool HasValue
{
get
{
return (_Value != null);
}
}
public T Value
{
get
{
if (!HasValue)
_Value = new T();
return _Value;
}
}
}
Now the MSDN Docs say that it's fine to have an [XmlElement("ElementName")] on a property and it does indeed seem to be able to deserialize just fine. The problem comes when I am serializing an object. I am running the following piece of code:
class SomeClass
{
[XmlElement("ExternalElementName")]
public ComplexElementType InternalElementName
{
get { return _InternalElementName.Value; }
}
protected Lazy<ComplexElementType> _InternalElementName;
}
Elsewhere:
SomeClass someClass = new SomeClass();
someClass.InternalElementName.ComplexElementTypeChild = "some string";
// serialize...
The strange thing is, this works fine in the debugger but no element is output in the XML. Non Lazy<T> elements work fine. Any ideas?
The problem is that the property has no setter. Even if it would be possible to get the value to serialise it, it can't be deserialised as there is no way to put the value back in the new object.
By design, XML Serialization will only serialize public read/write properties, and public fields.
Not sure what the problem is (I have always found the XML serializer behaviour to be shifty), but why not use the Nullable<T> class? Don't re-invent the wheel :)

Categories

Resources