uni
uni

Reputation: 623

XmlSerializer won't serialize IEnumerable

I have an invocation logger that is intended to record all method calls along with the parameters associated with the method using XmlSerializer. It works well for most of the calls, but it throws an exception for all methods that has a parameter of IEnumerable type.

For example, void MethodWithPlace( Place value ) would be serialized, but void MethodWithPlace( IEnumerable<Place> value ) would not.

The exception is

System.NotSupportedException: Cannot serialize interface System.Collections.Generic.IEnumerable`1[[Place, Test, Version=0.0.0.0, Culture=neutral]].

What should I do to make it work with those methods with IEnumerable as one of its parameters?

Upvotes: 47

Views: 44888

Answers (7)

Herman Schoenfeld
Herman Schoenfeld

Reputation: 8724

The way you serialize an IEnumerable property is with a surrogate property

[XmlRoot]
public class Entity {
   [XmlIgnore]
   public IEnumerable<Foo> Foo { get; set; }

   [XmlElement, Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
   public List<Foo> FooSurrogate { get { return Foo.ToList(); } set { Foo = value; } }
}

It's ugly, but it gets the job done. The nicer solution is to write a surrogate class (i.e. EntitySurrogate).

Upvotes: 35

Everson Rafael
Everson Rafael

Reputation: 2083

Maybe not the best way, but it worked for me. I created a method that makes serialization.

Use

var xml = Util.ObjetoToXML(obj, null, null).OuterXml;

method

        public static XmlDocument ObjetoToXML(object obj, XmlDocument xmlDocument, XmlNode rootNode)
    {

        if (xmlDocument == null)
            xmlDocument = new XmlDocument();

        if (obj == null) return xmlDocument;

        Type type = obj.GetType();

        if (rootNode == null) { 
            rootNode = xmlDocument.CreateElement(string.Empty, type.Name, string.Empty);
            xmlDocument.AppendChild(rootNode);
        }

        if (type.IsPrimitive || type == typeof(Decimal) || type == typeof(String) || type == typeof(DateTime))
        {

            // Simples types
            if (obj != null)
                rootNode.InnerText = obj.ToString();

        }
        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
        {
            // Genericis types

            XmlNode node = null;

            foreach (var item in (IEnumerable)obj)
            {
                if (node == null)
                {
                    node = xmlDocument.CreateElement(string.Empty, item.GetType().Name, string.Empty);
                    node = rootNode.AppendChild(node);
                }


                ObjetoToXML(item, xmlDocument, node);
            }

        }
        else
        {

            // Classes types
            foreach (var propertie in obj.GetType().GetProperties())
            {

                XmlNode node = xmlDocument.CreateElement(string.Empty, propertie.Name, string.Empty);
                node = rootNode.AppendChild(node);
                var valor = propertie.GetValue(obj, null);

                ObjetoToXML(valor, xmlDocument, node);
            }

        }


        return xmlDocument;

    }

Upvotes: 0

Maxim Eliseev
Maxim Eliseev

Reputation: 3504

You can use DataContractSerializer

        using (var ms = new MemoryStream())
        {
            var serialiser = new DataContractSerializer(typeof (EnvironmentMetadata));
            serialiser.WriteObject(ms, environmentMetadata);

            var s = Encoding.ASCII.GetString(ms.ToArray());
            return s;
        }

Upvotes: -3

what is sleep
what is sleep

Reputation: 905

To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object) at all levels of their inheritance hierarchy. {your class} does not implement Add(System.Object).

implement the Add() function, you might solve the problem

Upvotes: 3

Sina Iravanian
Sina Iravanian

Reputation: 16286

XmlSerializer does not support this. Try YAXLib for these kinds serializations.

Upvotes: 0

Chris
Chris

Reputation: 370

I don't think you'll be able to serialize that. Try converting the IEnumerable to a List and then you will be able to serialize.

Upvotes: 14

Kyle W
Kyle W

Reputation: 3752

Basically an XmlSerializer can't serialize an interface. The solution, then, is to give it a concrete instance to serialize. Depending on how your invocation logger works, I would consider using

var serializer = new XmlSerializer(value.GetType());

Upvotes: 13

Related Questions