views:

2121

answers:

3

Please consider the following Amount value type property which is marked as a nullable XmlElement:

[XmlElement(IsNullable=true)] 
public double? Amount { get ; set ; }

When a nullable value type is set to null, the C# XmlSerializer result looks like the following:

<amount xsi:nil="true" />

Rather than emitting this element, I would like the XmlSerializer to suppress the element completely. Why? We're using Authorize.NET for online payments and Authorize.NET rejects the request if this null element exists.

The current solution/workaround is to not serialize the Amount value type property at all. Instead we have created a complementary property, SerializableAmount, which is based on Amount and is serialized instead. Since SerializableAmount is of type String, which like reference types are suppressed by the XmlSerializer if null by default, everything works great.

/// <summary>
/// Gets or sets the amount.
/// </summary>
[XmlIgnore]
public double? Amount { get; set; }

/// <summary>
/// Gets or sets the amount for serialization purposes only.
/// This had to be done because setting value types to null 
/// does not prevent them from being included when a class 
/// is being serialized.  When a nullable value type is set 
/// to null, such as with the Amount property, the result 
/// looks like: &gt;amount xsi:nil="true" /&lt; which will 
/// cause the Authorize.NET to reject the request.  Strings 
/// when set to null will be removed as they are a 
/// reference type.
/// </summary>
[XmlElement("amount", IsNullable = false)]
public string SerializableAmount
{
    get { return this.Amount == null ? null : this.Amount.ToString(); }
    set { this.Amount = Convert.ToDouble(value); }
}

Of course, this is just a workaround. Is there a cleaner way to suppress null value type elements from being emitted?

+21  A: 

Try adding:

public bool ShouldSerializeAmount() {
   return Amount != null;
}

There are a number of patterns recognised by parts of the framework. For info, XmlSerializer also looks for public bool AmountSpecified {get;set;}.

Full example (also switching to decimal):

using System;
using System.Xml.Serialization;

public class Data {
    public decimal? Amount { get; set; }
    public bool ShouldSerializeAmount() {
        return Amount != null;
    }
    static void Main() {
        Data d = new Data();
        XmlSerializer ser = new XmlSerializer(d.GetType());
        ser.Serialize(Console.Out, d);
        Console.WriteLine();
        Console.WriteLine();
        d.Amount = 123.45M;
        ser.Serialize(Console.Out, d);
    }
}

More information on ShouldSerialize* on MSDN.

Marc Gravell
Hi Marc, that's why I love SO... You learn something like this. I have a couple of questions though. I can only find the following documentation of this feature in msdn: http://msdn.microsoft.com/en-us/library/53b8022e.aspx do you know of any *real* documentation?Also, since this feature is so poorly documented I would feel a bit dirty using it. Is it "safe" to use a seemingly undocumented feature like this?
JohannesH
Wow, that's what I'd call deeply obscure. Cool that you found it, though.
Steven Sudit
Thanks Marc. Now that you told me what to look for, I think I found the MSDN reference on XmlSerializer "property + specified" pattern. Here it is: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx. It's even difficult to find once you find the right MSDN reference page if you ask me. :) Thanks again.
Ben Griswold
Hmmm... I've looked, and I can't find anything more official... still looking.
Marc Gravell
And here's the MSDN reference for the ShouldSerialize pattern: http://msdn.microsoft.com/en-us/library/53b8022e(VS.71).aspx
Ben Griswold
(JohannesH already posted that; I assumed you meant "in the context of XmlSerializer")
Marc Gravell
+1 for the best answer.
Steven Sudit
Nice ! I thought I knew everything there was to know about XML serialization, but apparently I can still learn a few things...
Thomas Levesque
A: 

Hervorragenden Beitrag, hat mir geholfen viel, Danke!

Jemand