How can I force .NET\'s XmlSerializer to add an xsi:type=\"FooClass\" to a member/node of type FooClass?
The scenario
To support inheritance of types in other namespaces you need to use a solution similar to what Pavel Minaev suggested but with the XmlQualifiedName typed property instead of string, e.g.
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Test
{
///
/// Base class which is XML serializable and extensible.
///
[XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
public abstract class BaseClassInOtherNamespace
{
///
/// Name of the XML element
///
public const string XmlRootName = "Base";
///
/// XML namespace in which this type is defined.
///
public const string XmlRootNamespace = "urn:base";
///
/// Creates an instance which serializes as the correct inherited XML type.
///
protected BaseClassInOtherNamespace(XmlQualifiedName xsiType)
{
XsiType = xsiType;
}
///
/// XML type for serialization.
///
[XmlAttribute("type", Namespace = XmlSchema.InstanceNamespace)]
public XmlQualifiedName XsiType { get; set; }
///
/// Some base property.
///
public int BaseProperty { get; set; }
}
///
/// Inheriting class extending the base class, created in a different XML namespace.
///
[XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
[XmlType(XmlTypeName, Namespace = XmlTypeNamespace)]
public class InheritingClass : BaseClassInOtherNamespace
{
///
/// Name of the XML element
///
public const string XmlTypeName = "Inheriting";
///
/// XML namespace in which this type is defined.
///
public const string XmlTypeNamespace = "urn:other";
///
/// Creates an instance.
///
public InheritingClass() : base(new XmlQualifiedName(XmlTypeName, XmlTypeNamespace))
{
}
///
/// Some new property in a different (inheriting) namespace.
///
public int InheritingProperty { get; set; }
}
}
Will serialize (and de-serialize) correctly as:
0
0
This satisfies the requirement of truly extensible polymorphic XML types, i.e. the base class can be used anywhere and later add-ons can be assigned, serialized and de-serialized correctly in both .NET and with XSD validation.
Taking it further, you can also add a XmlSerializerNamespaces property with the XmlNamespaceDeclarationsAttribute to specify preferred prefixes and remove any unwanted namespaces, such as the xmlns:xsd (we only use xmlns:xsi) or even the XSI namespace for your non-inheriting XML serialized classes.