XML serialization of interface property

C#.NetSerialization

C# Problem Overview


I would like to XML serialize an object that has (among other) a property of type IModelObject (which is an interface).

public class Example
{
    public IModelObject Model { get; set; }
}

When I try to serialize an object of this class, I receive the following error:
"Cannot serialize member Example.Model of type Example because it is an interface."

I understand that the problem is that an interface cannot be serialized. However, the concrete Model object type is unknown until runtime.

Replacing the IModelObject interface with an abstract or concrete type and use inheritance with XMLInclude is possible, but seems like an ugly workaround.

Any suggestions?

C# Solutions


Solution 1 - C#

This is simply an inherent limitation of declarative serialization where type information is not embedded within the output.

On trying to convert <Flibble Foo="10" /> back into

public class Flibble { public object Foo { get; set; } }

How does the serializer know whether it should be an int, a string, a double (or something else)...

To make this work you have several options but if you truly don't know till runtime the easiest way to do this is likely to be using the XmlAttributeOverrides.

Sadly this will only work with base classes, not interfaces. The best you can do there is to ignore the property which isn't sufficient for your needs.

If you really must stay with interfaces you have three real options:

Hide it and deal with it in another property

Ugly, unpleasant boiler plate and much repetition but most consumers of the class will not have to deal with the problem:

[XmlIgnore()]
public object Foo { get; set; }

[XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized 
{ 
  get { /* code here to convert any type in Foo to string */ } 
  set { /* code to parse out serialized value and make Foo an instance of the proper type*/ } 
}

This is likely to become a maintenance nightmare...

Implement IXmlSerializable

Similar to the first option in that you take full control of things but

  • Pros
    • You don't have nasty 'fake' properties hanging around.
    • you can interact directly with the xml structure adding flexibility/versioning
  • Cons
  • you may end up having to re-implement the wheel for all the other properties on the class

Issues of duplication of effort are similar to the first.

Modify your property to use a wrapping type

public sealed class XmlAnything<T> : IXmlSerializable
{
    public XmlAnything() {}
    public XmlAnything(T t) { this.Value = t;}
    public T Value {get; set;}

    public void WriteXml (XmlWriter writer)
    {
        if (Value == null)
        {
            writer.WriteAttributeString("type", "null");
            return;
        }
        Type type = this.Value.GetType();
        XmlSerializer serializer = new XmlSerializer(type);
        writer.WriteAttributeString("type", type.AssemblyQualifiedName);
        serializer.Serialize(writer, this.Value);   
    }

    public void ReadXml(XmlReader reader)
    {
        if(!reader.HasAttributes)
            throw new FormatException("expected a type attribute!");
        string type = reader.GetAttribute("type");
        reader.Read(); // consume the value
        if (type == "null")
            return;// leave T at default value
        XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
        this.Value = (T)serializer.Deserialize(reader);
        reader.ReadEndElement();
    }

    public XmlSchema GetSchema() { return(null); }
}

Using this would involve something like (in project P):

public namespace P
{
    public interface IFoo {}
    public class RealFoo : IFoo { public int X; }
    public class OtherFoo : IFoo { public double X; }

    public class Flibble
    {
        public XmlAnything<IFoo> Foo;
    }


    public static void Main(string[] args)
    {
        var x = new Flibble();
        x.Foo = new XmlAnything<IFoo>(new RealFoo());
        var s = new XmlSerializer(typeof(Flibble));
        var sw = new StringWriter();
        s.Serialize(sw, x);
        Console.WriteLine(sw);
    }
}

which gives you:

<?xml version="1.0" encoding="utf-16"?>
<MainClass 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Foo type="P.RealFoo, P, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <RealFoo>
   <X>0</X>
  </RealFoo>
 </Foo>
</MainClass>

This is obviously more cumbersome for users of the class though avoids much boiler plate.

A happy medium may be merging the XmlAnything idea into the 'backing' property of the first technique. In this way most of the grunt work is done for you but consumers of the class suffer no impact beyond confusion with introspection.

Solution 2 - C#

The solution to this is using reflection with the DataContractSerializer. You don't even have to mark your class with [DataContract] or [DataMember]. It will serialize any object, regardless of whether it has interface type properties (including dictionaries) into xml. Here is a simple extension method that will serialize any object into XML even if it has interfaces (note you could tweak this to run recursively as well).

    public static XElement ToXML(this object o)
    {
        Type t = o.GetType();

        Type[] extraTypes = t.GetProperties()
            .Where(p => p.PropertyType.IsInterface)
            .Select(p => p.GetValue(o, null).GetType())
            .ToArray();

        DataContractSerializer serializer = new DataContractSerializer(t, extraTypes);
        StringWriter sw = new StringWriter();
        XmlTextWriter xw = new XmlTextWriter(sw);
        serializer.WriteObject(xw, o);
        return XElement.Parse(sw.ToString());
    }

what the LINQ expression does is it enumerates each property, returns each property that is an interface, gets the value of that property (the underlying object), gets the type of that concrete object puts it into an array, and adds that to the serializer's list of known types.

Now the serializer knows how about the types it is serializing so it can do its job.

Solution 3 - C#

If you know your interface implementors up-front there's a fairly simple hack you can use to get your interface type to serialize without writing any parsing code:

public interface IInterface {}
public class KnownImplementor01 : IInterface {}
public class KnownImplementor02 : IInterface {}
public class KnownImplementor03 : IInterface {}
public class ToSerialize {
  [XmlIgnore]
  public IInterface InterfaceProperty { get; set; }
  [XmlArray("interface")]
  [XmlArrayItem("ofTypeKnownImplementor01", typeof(KnownImplementor01))]
  [XmlArrayItem("ofTypeKnownImplementor02", typeof(KnownImplementor02))]
  [XmlArrayItem("ofTypeKnownImplementor03", typeof(KnownImplementor03))]
  public object[] InterfacePropertySerialization {
    get { return new[] { InterfaceProperty }; ; }
    set { InterfaceProperty = (IInterface)value.Single(); }
  }
}
  

The resulting xml should look something along the lines of

 <interface><ofTypeKnownImplementor01><!-- etc... -->

Solution 4 - C#

You can use ExtendedXmlSerializer. This serializer support serialization of interface property without any tricks.

var serializer = new ConfigurationContainer().UseOptimizedNamespaces().Create();

var obj = new Example
				{
					Model = new Model { Name = "name" }
				};

var xml = serializer.Serialize(obj);

Your xml will look like:

<?xml version="1.0" encoding="utf-8"?>
<Example xmlns:exs="https://extendedxmlserializer.github.io/v2" xmlns="clr-namespace:ExtendedXmlSerializer.Samples.Simple;assembly=ExtendedXmlSerializer.Samples">
	<Model exs:type="Model">
		<Name>name</Name>
	</Model>
</Example>

ExtendedXmlSerializer support .net 4.5 and .net Core.

Solution 5 - C#

> Replacing the IModelObject interface with an abstract or concrete type and use inheritance with XMLInclude is possible, but seems like an ugly workaround.

If it is possible to use an abstract base I would recommend that route. It will still be cleaner than using hand-rolled serialization. The only trouble I see with the abstract base is that your still going to need the concrete type? At least that is how I've used it in the past, something like:

public abstract class IHaveSomething
{
	public abstract string Something { get; set; }
}

public class MySomething : IHaveSomething
{
	string _sometext;
	public override string Something 
	{ get { return _sometext; } set { _sometext = value; } }
}

[XmlRoot("abc")]
public class seriaized
{
	[XmlElement("item", typeof(MySomething))]
	public IHaveSomething data;
}

Solution 6 - C#

Unfortunately there's no simple answer, as the serializer doesn't know what to serialize for an interface. I found a more complete explaination on how to workaround this on MSDN

Solution 7 - C#

Unfortuantely for me, I had a case where the class to be serialized had properties that had interfaces as properties as well, so I needed to recursively process each property. Also, some of the interface properties were marked as [XmlIgnore], so I wanted to skip over those. I took ideas that I found on this thread and added some things to it to make it recursive. Only the deserialization code is shown here:

void main()
{
	var serializer = GetDataContractSerializer<MyObjectWithCascadingInterfaces>();
	using (FileStream stream = new FileStream(xmlPath, FileMode.Open))
	{
		XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
		var obj = (MyObjectWithCascadingInterfaces)serializer.ReadObject(reader);
	
		// your code here
	}
}

DataContractSerializer GetDataContractSerializer<T>() where T : new()
{
	Type[] types = GetTypesForInterfaces<T>();

	// Filter out duplicates
	Type[] result = types.ToList().Distinct().ToList().ToArray();

	var obj = new T();
	return new DataContractSerializer(obj.GetType(), types);
}

Type[] GetTypesForInterfaces<T>() where T : new()
{
	return GetTypesForInterfaces(typeof(T));
}

Type[] GetTypesForInterfaces(Type T)
{
	Type[] result = new Type[0];
	var obj = Activator.CreateInstance(T);

	// get the type for all interface properties that are not marked as "XmlIgnore"
	Type[] types = T.GetProperties()
		.Where(p => p.PropertyType.IsInterface && 
			!p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false).Any())
		.Select(p => p.GetValue(obj, null).GetType())
		.ToArray();

	result = result.ToList().Concat(types.ToList()).ToArray();

	// do the same for each of the types identified
	foreach (Type t in types)
	{
		Type[] embeddedTypes = GetTypesForInterfaces(t);
		result = result.ToList().Concat(embeddedTypes.ToList()).ToArray();
	}
	return result;
}

Solution 8 - C#

I have found a simpler solution (you don't need the DataContractSerializer), thanks to this blog here: [XML serializing derived types when base type is in another namespace or DLL][1]

> But 2 problems can rise in this implementation: > > (1) What if DerivedBase is not in the namespace of class Base, or even worse in a project that depends on Base namespace, so Base cannot XMLInclude DerivedBase > > (2) What if we only have class Base as a dll ,so again Base cannot XMLInclude DerivedBase > > Till now, ... > > So the solution to the 2 problems is by using XmlSerializer Constructor (Type, array[]) :

XmlSerializer ser = new XmlSerializer(typeof(A), new Type[]{ typeof(DerivedBase)});

A detailed example is provided here on MSDN: [XmlSerializer Constructor (Type, extraTypesArray[])][2]

It seems to me that for DataContracts or Soap XMLs, you need to [check the XmlRoot as mentioned here in this SO question][3].

A [similar answer is here on SO][4] but it isn't marked as one, as it not the OP seems to have considered it already.

[1]: https://ozba.wordpress.com/2009/09/22/xml-serialization-derived-types-problem-can-be-resolved/ "XML serializing derived types" [2]: https://msdn.microsoft.com/en-us/library/e5aakyae(v=vs.90).aspx [3]: https://stackoverflow.com/questions/4616505/is-there-a-reason-why-a-base-class-decorated-with-xmlinclude-would-still-throw-a [4]: https://stackoverflow.com/questions/11886290/use-the-xmlinclude-or-soapinclude-attribute-to-specify-types-that-are-not-known

Solution 9 - C#

in my project, I have a
List<IFormatStyle> FormatStyleTemplates;
containing different Types.

I then use the solution 'XmlAnything' from above, to serialize this list of different types. The generated xml is beautiful.

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [XmlArray("FormatStyleTemplates")]
    [XmlArrayItem("FormatStyle")]
    public XmlAnything<IFormatStyle>[] FormatStyleTemplatesXML
    {
        get
        {
            return FormatStyleTemplates.Select(t => new XmlAnything<IFormatStyle>(t)).ToArray();
        }
        set
        {
            // read the values back into some new object or whatever
            m_FormatStyleTemplates = new FormatStyleProvider(null, true);
            value.ForEach(t => m_FormatStyleTemplates.Add(t.Value));
        }
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEladView Question on Stackoverflow
Solution 1 - C#ShuggyCoUkView Answer on Stackoverflow
Solution 2 - C#DespertarView Answer on Stackoverflow
Solution 3 - C#hannasmView Answer on Stackoverflow
Solution 4 - C#Wojtpl2View Answer on Stackoverflow
Solution 5 - C#csharptest.netView Answer on Stackoverflow
Solution 6 - C#MattHView Answer on Stackoverflow
Solution 7 - C#acordnerView Answer on Stackoverflow
Solution 8 - C#B Charles HView Answer on Stackoverflow
Solution 9 - C#Detlef KrollView Answer on Stackoverflow