Question40998611 custom-xml-deserialization-runs-into-an-endless-loop

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

using Newtonsoft.Json;

using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Schema;

// https://stackoverflow.com/questions/40998611/custom-xml-deserialization-runs-into-an-endless-loop

    public class ParentEntity
    {
        public ParentEntity() { Childs = new List<ChildEntity>(); }
        public List<ChildEntity> Childs { get; set; }
    }

    public class ChildEntity : IXmlSerializable
    {
        public string Name { get; set; }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            Name = reader.GetAttribute("Name");
            reader.Skip(); // Consume the <ChildEntity> and </ChildEntity> (if present) nodes and everything contained therein.
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("Name", Name);
        }
    }

    class TestClass
    {
        public static void Test()
        {
            var parent = new ParentEntity { Childs = { new ChildEntity { Name = "hello" }, new ChildEntity { Name = "there" } } };

            var xml = parent.GetXml();

            Console.WriteLine("Testing round-trip... ");
            var xml2 = Test(parent, xml);

            if (xml2 != xml)
            {
                throw new InvalidOperationException("xml2 != xml");
            }

            var element = XElement.Parse(xml2);
            element.Elements("Childs").Elements("ChildEntity").ElementAt(1).Add(new XElement("DummyElementThatShouldBeIgnored"));
            var xml3 = element.ToString();

            Console.WriteLine("Testing round-trip with dummy child element added that should be ignored... ");
            Test(parent, xml3);

            var xml4 = XDocument.Parse(xml).ToString(SaveOptions.DisableFormatting);

            Console.WriteLine("Testing round-trip with no formatting... ");
            Test(parent, xml4);

            Console.WriteLine("Success.");
        }

        private static string Test(ParentEntity parent, string testInputXml)
        {
            Console.WriteLine(testInputXml);
            var newParent = testInputXml.LoadFromXml<ParentEntity>();
            if (JsonConvert.SerializeObject(parent) != JsonConvert.SerializeObject(newParent))
            {
                throw new InvalidOperationException("JsonConvert.SerializeObject(parent) != JsonConvert.SerializeObject(newParent)");
            }
            if (!parent.Childs.Select(c => c.Name).SequenceEqual(newParent.Childs.Select(c => c.Name)))
            {
                throw new InvalidOperationException("!parent.Childs.Select(c => c.Name).SequenceEqual(newParent.Childs.Select(c => c.Name))");
            }

            return parent.GetXml();
        }
    }
					
	public class Program
	{
		public static void Main()
		{
			TestClass.Test();
		}
	}

    public static class XmlSerializationHelper
    {
        public static T LoadFromXml<T>(this string xmlString)
        {
            using (StringReader reader = new StringReader(xmlString))
            {
                return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
            }
        }

        public static string GetXml<T>(this T obj, bool omitStandardNamespaces = false)
        {
            XmlSerializerNamespaces ns = null;
            if (omitStandardNamespaces)
            {
                ns = new XmlSerializerNamespaces();
                ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            }			
            using (var textWriter = new StringWriter())
            {
                var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
                using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                    new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj, ns);
                return textWriter.ToString();
            }
        }
    }
;