WinRT XmlAnyElement and Serialization

294 views Asked by At

We have a Windows Store application that communicates with our server using XML for requests / responses and are serialized with the XmlSerializer. The issue we are encountering is that one of our types can contain arbitrary XML as one of its properties. In non WinRT applications, the usage would have been.

public sealed ItemExtension {
    [XmlAttribute("source")]
    public string Source {get;set;}

    [XmlAnyElement]
    public XmlElement[] Data {get;set;}
}

This would allow us to have XML in our database like

<extension source="foo"><randomXml><data/></randomXml></extension>

In WinRT, XmlElement is not included, System.Xml.XmlElement does not exist and the Windows.Data.Xml.Dom.XmlElement is not compatible. Documentation mentions XElement, but XElement is not a supported WinRT type so the WinRT project won't compile if I try using it.

Is this a bug with Windows Store applications or is there a sufficient work around?

Thanks.

1

There are 1 answers

0
littlepod On BEST ANSWER

So far I've only found a hack to get this working. If we use

[XmlAnyElement]
public object Data {get;set;}

This will properly will properly deserialize existing data. In the debugger when inspecting it, it is of type System.Xml.XmlElement, which isn't exposed in WinRT. So there's no way to directly set this. Since we figured out that XmlSerializer can instantiate and access System.Xml.XmlElement, we use it to handle setting it by taking in an object/xml snippet, wrapping it in container xml for a wrapper type that contains [XmlAnyElement] and calling Deserialize on it to have the XmlSerializer instantiate an XmlElement, which can then be set on the target object you wish to serialize.

For getting data, since trying to read this property throws an exception in the UI layer, and trying to access InnerXml/OuterXml throw an exception as well, we are left with using the XmlSerializer to Serialize the XmlElement back into a string, and then can use that however you want.

public sealed class XmlAnyElementContainer
{
    [XmlAnyElement]
    public object Data { get; set; }
}

public void SetData(object extensionObject)
{
    var objectSerializer = new XmlSerializer(extensionObject.GetType());

    var settings = new XmlWriterSettings()
    {
        Indent = false,
        OmitXmlDeclaration = true
    };

    var sb = new StringBuilder();
    using (var xmlWriter = XmlWriter.Create(sb, settings))
    {
        objectSerializer.Serialize(xmlWriter, extensionObject);
    }

    string objectXml = sb.ToString();

    string newXml = "<XmlAnyElementContainer>" + objectXml + "</XmlAnyElementContainer>";
    var xmlAnySerializer = new XmlSerializer(typeof(XmlAnyElementContainer));
    using (var sr = new StringReader(newXml))
    {
        [TargetPropertyToSerialize] = (xmlAnySerializer.Deserialize(sr) as XmlAnyElementContainer).Data;
    }
}