2

Imagine this is my scenario:

public abstract class Foo
{
    public abstract int X { get; set; }
}

public class FooA : Foo
{
    public override int X { get; set; }
    public int Y { get; set; }
}

public class FooB : Foo
{
    public override int X { get; set; }
    public int Z { get; set; }
}

This is a service where I've got some objects to serialize.

public class FooService
{
    public List<Foo> GetModels()
    {
        return new List<Foo>()
        {
            new FooA() { X = 3, Y = 6 },
            new FooB() { X = 5, Z = 10 }
        };
    }
}

And this is the method where I can't serialize my objects, it throws an exception. I want to serialize derived classes.

    private void SerializeObjects()
    {
        FooService service = new FooService();
        var a = service.GetModels();

        XmlSerializer x = new XmlSerializer(a.GetType());
        TextWriter writer = new StreamWriter("A.xml");

        x.Serialize(writer, a);
        writer.Close();
    }
Steve Wellens
  • 20,506
  • 2
  • 28
  • 69
Darf Zon
  • 6,268
  • 20
  • 90
  • 149
  • What is the exception? What have you tried? – dee-see Mar 22 '12 at 21:19
  • What's the exception text? I bet it's complaining about known types and telling you what to do about it. – Eric J. Mar 22 '12 at 21:20
  • @Vache this is my error: There was an error generating the XML document. – Darf Zon Mar 22 '12 at 21:24
  • There's no XML Attribute declarations on any of those classes. You have to tell the serializer what to serialise by decorating properties and attributes of Foo, FooA, FooB etc – dreza Mar 22 '12 at 21:24
  • 1
    And the inner exception tells you to `"The type FooA was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."` :-) – Eric J. Mar 22 '12 at 21:25
  • @EricJ. It works :), allow me to make clear my situation. I've got a library where it has ´Foo´, and another modules contains FooA and FooB. I mean, I need to create many modules and I don't prefer put those Includes.. what might I do? – Darf Zon Mar 22 '12 at 21:28
  • @DarfZon Use some other serializers like [Json.Net](http://json.codeplex.com/) – L.B Mar 22 '12 at 21:31
  • @L.B: Json.Net can handle types that are not statically known? DataContractSerializer cannot... would surprise me if Json.Net can. – Eric J. Mar 27 '12 at 14:54
  • @DarfZon: Added more info to the answer based on "many modules" – Eric J. Mar 27 '12 at 14:59
  • @EricJ. This is the output `[{"X":3,"Y":6},{"X":5,"Z":10}]` of `JsonConvert.SerializeObject(service.GetModels())` – L.B Mar 27 '12 at 15:12

2 Answers2

12

You have to tell the serializer about the derived types

[XmlInclude(typeof(FooA))]
[XmlInclude(typeof(FooB))]
public abstract class Foo
{
    public abstract int X { get; set; }
}

This is one of the choice .Net exceptions that are truly helpful. If you look at the InnerException, you will see

The type FooA was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

UPDATE

Based on your comment about many derived types in different modules, you can also specify derived types at runtime when creating the serializer rather than at compile time:

How to add XmlInclude attribute dynamically

Community
  • 1
  • 1
Eric J.
  • 147,927
  • 63
  • 340
  • 553
0

Here is a nice reusable method:

string sSerialData = "";

SerializeQueueType<BaseClassType>(oDerivedObject, out sSerialData)


private bool SerializeDerivedObject<T>(T oDerivedObject, out string sOutput)
{
    bool bReturn = false;

    sOutput = "";

    try
    {

        Type[] arrTypes = new Type[1];
        arrTypes[0] = oDerivedObject.GetType();

        XmlSerializer xmlSerl = new XmlSerializer(typeof(T), arrTypes); 
        System.IO.MemoryStream memStream = new System.IO.MemoryStream();
        xmlSerl.Serialize(memStream, oDerivedObject); 

        memStream.Position = 0;

        using (var reader = new System.IO.StreamReader(memStream, Encoding.UTF8))
        {
            sOutput = reader.ReadToEnd();
        }

        bReturn = true;

    }
    catch (Exception ex)
    {
        //_log.Error(ex);
    }


    return bReturn;

} 
WoodsLink
  • 107
  • 5