views:

49

answers:

1

UPDATE: You can run the code at the end of this to recreate and see the error I am having and hopefully solve it!

UPDATE2: It's not the removal of the xmlns="" that's the issue... as you can remove it from the initial xml string. The problem is with the [XmlType(TypeName = "Systems")] somehow causing it to be added...

UPDATE3: Turns out the problem is in here, I need to set the TypeName based on what is in the existing, XmlTypeAttribute if it already exists on the class....

    xmlAttributes.XmlType = new XmlTypeAttribute
    {
        Namespace = ""
    };

I get the following XML as a string from a webservice

<Systems xmlns="">
  <System id="1">
    <sys_name>ALL</sys_name>
  </System>
  <System id="2">
    <sys_name>asdfasdf</sys_name>
  </System>
  <System id="3">
    <sys_name>fasdfasf</sys_name>
  </System>
  <System id="4">
    <sys_name>asdfasdfasdf</sys_name>
  </System>
</Systems>

I then execute this, to convert it to an object

result = XElement.Parse(xmlResult.OuterXml).Deserialize<AwayRequestSystems>();

Strangely though, in the Deserialize method, while the RemoveAllNamespaces works and returns the xml without the namespace

I get the error <Systems xmlns=''> was not expected. in the catch when return (T) serializer.Deserialize(reader); executes!

Why is it doing this? The xmlns is GONE!!!

EXECUTABLE CODE! (Just put it in a test project)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Serialization;

namespace DeserializationTest
{
    [TestClass]
    public class UnitTest1
    {
    public TestContext TestContext { get; set; }

    [TestMethod]
    public void RemoveXmlnsFromSystems()
    {
        var xml = XElement.Parse(@"<Systems xmlns="""">
                      <System id=""1"">
                        <sys_name>ALL</sys_name>
                      </System>
                      <System id=""2"">
                        <sys_name>ePO</sys_name>
                      </System>
                      <System id=""3"">
                        <sys_name>iEFT</sys_name>
                      </System>
                      <System id=""4"">
                        <sys_name>Away Requests</sys_name>
                      </System>
                      <System id=""5"">
                        <sys_name>RP3</sys_name>
                      </System>
                    </Systems>");

        var systems = xml.Deserialize<AwayRequestSystems>();
        Assert.IsInstanceOfType(systems, typeof(AwayRequestSystems));

        var xmlnsFree = xml.RemoveAllNamespaces();
        var str = xmlnsFree.ToString();

        Debug.WriteLine(str);

        Assert.AreNotEqual("Error", xmlnsFree.Name.ToString(), "Serialization Error");
        Assert.IsFalse(str.Contains("xmlns"), "Xmlns still exists");
    }
    }


    [XmlType(TypeName = "Systems")]
    public class AwayRequestSystems : List<AwayRequestSystem> { }

    [XmlType(TypeName = "System")]
    public class AwayRequestSystem
    {
    [XmlAttribute("id")]
    public int ID { get; set; }

    [XmlElement("sys_name")]
    public string Name { get; set; }
    }

    public static class XmlSerializerFactory
    {
    private static Dictionary<Type, XmlSerializer> _serializers = new Dictionary<Type, XmlSerializer>();

    public static void ResetCache()
    {
        _serializers = new Dictionary<Type, XmlSerializer>();
    }

    public static XmlSerializer GetSerializerFor(Type typeOfT)
    {
        if (!_serializers.ContainsKey(typeOfT))
        {
        var xmlAttributes = new XmlAttributes();
        var xmlAttributeOverrides = new XmlAttributeOverrides();

        Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));

        xmlAttributes.XmlType = new XmlTypeAttribute
        {
            Namespace = ""
        };

        xmlAttributes.Xmlns = false;

        var types = new List<Type> { typeOfT, typeOfT.BaseType };

        foreach (var property in typeOfT.GetProperties())
        {
            types.Add(property.PropertyType);
        }

        types.RemoveAll(t => t.ToString().StartsWith("System."));

        foreach (var type in types)
        {
            if (xmlAttributeOverrides[type] == null)
            xmlAttributeOverrides.Add(type, xmlAttributes);
        }

        var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
        //var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, types.ToArray(), new XmlRootAttribute(), string.Empty);
        //var newSerializer = new XmlSerializer(typeOfT, string.Empty);

        _serializers.Add(typeOfT, newSerializer);
        }

        return _serializers[typeOfT];
    }
    }

    public static class XElementExtensions
    {
    public static XElement RemoveAllNamespaces(this XElement source)
    {
        if (source.HasAttributes)
        source.Attributes().Where(a => a.Name.LocalName.Equals("xmlns")).Remove();

        return source.HasElements
               ? new XElement(source.Name.LocalName,
                      source.Attributes()/*.Where(a => !a.Name.LocalName.Equals("xmlns"))*/,
                      source.Elements().Select(el => RemoveAllNamespaces(el))
                 )
               : new XElement(source.Name.LocalName)
                 {
                 Value = source.Value
                 };
    }
    }

    public static class SerializationExtensions
    {
    public static XElement Serialize(this object source)
    {
        try
        {
        var serializer = XmlSerializerFactory.GetSerializerFor(source.GetType());
        var xdoc = new XDocument();
        using (var writer = xdoc.CreateWriter())
        {
            serializer.Serialize(writer, source, new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") }));
        }

        var result = (xdoc.Document != null) ? xdoc.Document.Root : new XElement("Error", "Document Missing");

        return result.RemoveAllNamespaces();
        }
        catch (Exception x)
        {
        return new XElement("Error", x.ToString());
        }
    }

    public static T Deserialize<T>(this XElement source) where T : class
    {
        //try
        //{
        var serializer = XmlSerializerFactory.GetSerializerFor(typeof(T));

        var cleanxml = source.RemoveAllNamespaces();
        var reader = cleanxml.CreateReader();

        return (T)serializer.Deserialize(reader);
        //}
        //catch (Exception x)
        //{
        //    return null;
        //}
    }
    }
}
+1  A: 

The problem as it turns out was because I was losing the TypeName attribute when removing namespaces with this line

xmlAttributes.XmlType = new XmlTypeAttribute
{
    Namespace = ""
};

I changed the GetSerializerFor class in the factory to the following and it now works

   public static XmlSerializer GetSerializerFor(Type typeOfT)
    {
        if (!_serializers.ContainsKey(typeOfT))
        {
            Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));

            var types = new List<Type> { typeOfT, typeOfT.BaseType };

            foreach (var property in typeOfT.GetProperties())
            {
                types.Add(property.PropertyType);
            }

            types.RemoveAll(t => t.ToString().StartsWith("System."));

            var xmlAttributeOverrides = new XmlAttributeOverrides();
            foreach (var type in types)
            {
                if (xmlAttributeOverrides[type] != null) 
                    continue;

                var xmlAttributes = new XmlAttributes
                                        {
                                            XmlType = new XmlTypeAttribute
                                                          {
                                                              Namespace = "",
                                                              TypeName = GetSerializationTypeName(type)
                                                          },
                                            Xmlns = false
                                        };
                xmlAttributeOverrides.Add(type, xmlAttributes);
            }

            var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
            //var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, types.ToArray(), new XmlRootAttribute(), string.Empty);
            //var newSerializer = new XmlSerializer(typeOfT, string.Empty);

            _serializers.Add(typeOfT, newSerializer);
        }

        return _serializers[typeOfT];
    }

    private static string GetSerializationTypeName(Type type)
    {
        var xmlTypeAttribute = TypeDescriptor.GetAttributes(type)
            .OfType<XmlTypeAttribute>().FirstOrDefault();

        var typeName = xmlTypeAttribute.TypeName;
        return string.IsNullOrEmpty(typeName) ? type.Name : typeName;
    }
Chad