After posting my problems with the XML serializer yesterday, Scott Hanselman blogged a possible solution for the bug and a further explanation of what to look for in the serializer. Now I'm not one to quibble here with whether or not the .NET 2.0 serializer \ xsd.exe should be intelligent enough to figure out that the generic case for serialization should appear last in a series of if statements or whether I've been riding my luck with the .NET 1.1 serializer for the last sixteen months, and thus whether or not it counts as a bug, but I was happy enough to accept it if it did the trick. To recall the solution, given the following schema declaration

<element name="epp" type="epp:eppType" />
<complexType name="eppType">
  <choice>
    <element name="hello" />
    <element name="greeting" type="epp:greetingType" />
  </choice>
</complexType>

running xsd.exe produces the following class.

[System.Xml.Serialization.XmlTypeAttribute
   (Namespace = "urn:ietf:params:xml:ns:epp-1.0", TypeName = "eppType")]
[System.Xml.Serialization.XmlRootAttribute
   ("epp", Namespace = "urn:ietf:params:xml:ns:epp-1.0", IsNullable = false)]
public class EppType
{
   private object item;

   [System.Xml.Serialization.XmlElementAttribute
      ("hello", typeof(object))]
   [System.Xml.Serialization.XmlElementAttribute
      ("greeting", typeof(GreetingType))]
   public object Item
   {
      get { return this.item; }
      set { this.item = value; }
   }
}

The issue is that the two XmlElementAttributes should be switched around like so

[System.Xml.Serialization.XmlElementAttribute
   ("greeting", typeof(GreetingType))]
[System.Xml.Serialization.XmlElementAttribute
   ("hello", typeof(object))]
public object Item

to produce the correct decision semantics in the runtime generated serializer code for the class. Sure enough (after misreading his post once and going nowhere in a fit of hopeful excitement) Scott's suggestion worked on my reduced demo code. Time to apply it to the actual solution code and hope it continued to work. I decided first to reflect the genuine EPP Core Schema (RFC3730) in the demo code. The full schema actually contains five possible choices for an <epp> element...

<element name="epp" type="epp:eppType" />
<complexType name="eppType">

  <choice>
    <element name="greeting" type="epp:greetingType" />
    <element name="hello" />
    <element name="command" type="epp:commandType" />
    <element name="response" type="epp:responseType" />
    <element name="extension" type="epp:extAnyType" />
  </choice>
</complexType>

... but the principle should be the same. If I switch the XmlElementAttribute for hello to the bottom of the stack like so, the serializer if statements correspond to the attribute stack and the generic object comparison goes last.

[System.Xml.Serialization.XmlElementAttribute
  ("greeting", typeof(GreetingType))]
[System.Xml.Serialization.XmlElementAttribute
  ("command", typeof(EppCommandType))]
[System.Xml.Serialization.XmlElementAttribute
  ("response", typeof(ResponseType))]
[System.Xml.Serialization.XmlElementAttribute
  ("extension", typeof(ExtAnyType))]
[System.Xml.Serialization.XmlElementAttribute
  ("hello", typeof(object))]
public object Item {
   get {
       return this.item;
   }
   set {
       this.item = value;
   }
}

Unfortunately not. OK, time to roll out Scott's way to debug the XML Serializer against the two debug builds with the hello attribute at the top of the stack and at the bottom of the stack. I end up getting the below comparison. The working code generated with hello on top is on the right and the failing code for the hello on the bottom of the stack is on the left.

winmerge1_4

What’s immediately apparent is that neither set of if statements here match the order in which the stack is written in the source code and, ironically, the if statement for hello is at the bottom of the stack in the right hand pane where the elementattribute for hello was on the top of the stack in the original code. To see if this was an arbitrary placing of the if statements in the serializer dll, I moved the hello attribute up the stack one place at a time, rebuilt and viewed the temp dll code and the order of the ifs never matched the attribute stack. More annoyingly, I didn't (through luck or otherwise) get the if statement for hello to appear as the last of the if statements in the DLL again which would produce exactly the required results.

Using their initials as abbreviation, these are the results I got.

Order in the attribute stack (top first) Order of if statements in serializer DLLs (top first)
H-G-R-C-E (as generated by xsd.exe) G-E-R-C-H (which would work)
G-R-C-E-H (as suggested by Scott) E-C-G-H-R
G-H-R-C-E (matching EPP schema) G-E-H-C-R
G-R-H-C-E H-E-G-C-R
G-R-C-H-E E-H-G-C-R
G-R-C-E-H (should match earlier results) E-C-G-H-R (yup)

Which made me wonder about the original choice-of-two example. Rather than switching the hello and greeting attributes around and rebuilding enough times probably wouldn't cause the bug to occur with hello underneath greeting in the attribute stack of two but creating it from scratch a few times might. My initial sample code to Scott it seems wasn't demonstrative enough. Apologies Scott. My bad.