How to deserialize XML if the return type could be an Error or Success object

In situations where you have an XML stream containing one of several possible document types, you can construct an XmlSerializer for each type and call XmlSerializer.CanDeserialize(XmlReader) to successively test whether the document can be deserialized into that type. This method does not advance the XmlReader past the root element so it can be called multiple times without re-reading the stream.

For instance, you could introduce the following extension method:

public static partial class XmlSerializerExtensions
{
    public static object DeserializePolymorphicXml(this string xml, params Type[] types)
    {
        using (var textReader = new StringReader(xml))
        {
            return textReader.DeserializePolymorphicXml(types);
        }
    }

    public static object DeserializePolymorphicXml(this TextReader textReader, params Type[] types)
    {
        if (textReader == null || types == null)
            throw new ArgumentNullException();
        var settings = new XmlReaderSettings { CloseInput = false }; // Let caller close the input.
        using (var xmlReader = XmlReader.Create(textReader, settings))
        {
            foreach (var type in types)
            {
                var serializer = new XmlSerializer(type);
                if (serializer.CanDeserialize(xmlReader))
                    return serializer.Deserialize(xmlReader);
            }
        }
        throw new XmlException("Invalid root type.");
    }
}

Then use it as follows:

var xmlBody = result.ResponseBody.DeserializePolymorphicXml(typeof(SuccessResponse), typeof(FailResponse));
if (xmlBody is SuccessResponse)
{
    // Handle successful response
}
else if (xmlBody is FailResponse)
{
    // Handle failed response
}
else
{
    // unknown response
    throw new InvalidOperationException("unknown response");
}

Sample fiddle.

Leave a Comment