How to solve "Both use the XML type name X, use XML attributes to specify a unique XML name and/or namespace for the type"?

11,647

Solution 1

You need to provide the Namespace by using the XmlElement attribute on the properties of your UISettings class:

public class UISettings
{
    public UISettings()
    {

        ItemTable = new ItemTable();
        EffectiveItemPermissionTable = new EffectiveItemPermissionTable();
    }
    [XmlElement(Namespace = "Item")]
    public ItemTable ItemTable { get; set; }
    [XmlElement(Namespace = "Permissions")]
    public EffectiveItemPermissionTable EffectiveItemPermissionTable { get; set; }
}

When applied here this will be your serialized output:

<?xml version="1.0" encoding="utf-16"?>
<UISettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
   <ItemTable xmlns="Item">    
      <DisplayMode>Tiles</DisplayMode>  
   </ItemTable>  
   <EffectiveItemPermissionTable xmlns="Permissions">    
       <DisplayMode>FullPaths</DisplayMode>  
   </EffectiveItemPermissionTable>
</UISettings>

Alternatively, and maybe cleaner, you can provide the Namespace on the types:

[XmlType(Namespace="Item")]
public class ItemTable : Table<ItemTableNS.DisplayMode>
{ }

[XmlType(Namespace = "Permission")]
public class EffectiveItemPermissionTable : Table<EffectiveItemPermissionTableNS.DisplayMode>
{ }

This will serialize as:

<?xml version="1.0" encoding="utf-16"?>
<UISettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ItemTable>
    <DisplayMode xmlns="Item">Tiles</DisplayMode>
  </ItemTable>
  <EffectiveItemPermissionTable>
    <DisplayMode xmlns="Permission">FullPaths</DisplayMode>
  </EffectiveItemPermissionTable>
</UISettings>

Solution 2

I realize this answer probably comes way too late for the OP, but there is a way to do this without using namespaces, so I'm going to leave an answer here in case somebody comes along after me and needs the solution.

The problem is caused by the fact that the way the XmlSerializer names a type X<Y> is by giving it the name XOfY. Thus, when you have two types that both derive from Table<TDisplayMode>, you get that error, since they'll both be known internally as TableOfDisplayMode, despite actually using different enums.

This is because ItemTable and EffectiveItemPermissionTableare actually not inheriting from the same type! One inherits from Table<ItemTable.DisplayMode> and the other from Table<EffectiveItemPermissionTable.DisplayMode>. Not that this is limited to inheritance; you'd face the same problem if you tried to use them directly in the same XML object graph also.

Now, for the non-generic counterpart to this problem, you'd just smack an [XmlType] on the two types, and call it a day. But you can't do that here. While Table<ItemTable.DisplayMode> and Table<EffectiveItemPermissionTable.DisplayMode> are different types, they share the same class definition, so by trying to use [XmlType], you're giving them a different name, but still the same name.

So what can you do? XmlAttributeOverrides to the rescue! It lets you override the names the XmlSerializer gives to closed generic types, meaning that you can finally give a different name to Table<ItemTable.DisplayMode> and Table<EffectiveItemPermissionTable.DisplayMode>:

var xmlOverrides = new XmlAttributeOverrides();

var xmlAttribs = new XmlAttributes();   
xmlAttribs.XmlType = new XmlTypeAttribute("TableOfItemTableDisplayMode");
xmlOverrides.Add(typeof(Table<ItemTable.DisplayMode>), xmlAttribs);

xmlAttribs = new XmlAttributes();
xmlAttribs.XmlType = new XmlTypeAttribute("TableOfEffectiveItemPermissionTableDisplayMode");
xmlOverrides.Add(typeof(Table<EffectiveItemPermissionTable.DisplayMode>), xmlAttribs);

System.Xml.Serialization.XmlSerializer lSerializer =
    new System.Xml.Serialization.XmlSerializer(typeof(UISettings), xmlOverrides);

And voilà! Assuming now that you've also put [XmlType] with different names for your DisplayMode enums, so that their names don't conflict either, you've got yourself a working setup!

Share:
11,647

Related videos on Youtube

ViRuSTriNiTy
Author by

ViRuSTriNiTy

Updated on September 16, 2022

Comments

  • ViRuSTriNiTy
    ViRuSTriNiTy over 1 year

    I have the following enum definitions...

    namespace ItemTable
    {
      public enum DisplayMode
      {
        Tiles,
        Default
      }
    }
    
    namespace EffectiveItemPermissionTable
    {
      public enum DisplayMode
      {
        Tree,
        FullPaths
      }
    }
    

    ...and then i have the following classes...

    public class Table<TDisplayMode>
      where TDisplayMode: struct
    {
      // public
        public TDisplayMode DisplayMode
        { 
          get { return mDisplayMode; }
          set { mDisplayMode = value; }
        }
    
      // private
        private TDisplayMode mDisplayMode;
    }
    
    public class ItemTable : Table<ItemTable.DisplayMode>
    {}
    
    public class EffectiveItemPermissionTable : Table<EffectiveItemPermissionTable.DisplayMode>
    {}
    
    public class UISettings
    {
      public UISettings()
      {
        ItemTable = new ItemTable();
        EffectiveItemPermissionTable = new EffectiveItemPermissionTable();
      }
    
      public ItemTable ItemTable { get; set; }
      public EffectiveItemPermissionTable EffectiveItemPermissionTable { get; set; }
    }
    

    ...and when i try to serialize an instance of UISettings with...

    System.Xml.Serialization.XmlSerializer lSerializer =
      new System.Xml.Serialization.XmlSerializer(typeof(UISettings));
    

    ...i get the following error:

    Types 'UISettings.Table`1[EffectiveItemPermissionTable.DisplayMode]' and
    'UISettings.Table`1[ItemTable.DisplayMode]' both use the XML type name,
    'TableOfDisplayMode', from namespace ''.
    
    Use XML attributes to specify a unique XML name and/or namespace for the type.
    

    I have tried to use XmlType attribubtes and all sorts of solutions posted on the web but nothing works. The XML type name is always TableOfDisplayMode as mentioned in the error.

    The only solution right now is to rename one of the enums, e.g. to DisplayMode_ but I find that rather ugly.

  • ViRuSTriNiTy
    ViRuSTriNiTy over 7 years
    Oh my...works! Thx. But why do i need to specify a namespace? Why doesn't the serializer just use the property name as namespace?
  • rene
    rene over 7 years
    Well, the serializer doesn't use namespaces by default and generating them when needed would probably break more scenario's. Namespaces are in that sense similar to namespaces in c#. it does matter if Label is coming from the System.Windows.Forms or System.Web.WebControls namespace.
  • ViRuSTriNiTy
    ViRuSTriNiTy over 7 years
    Ok, but why is it even necessary to add a xmlns attribute to the DisplayMode nodes? Any specific reason?
  • rene
    rene over 7 years
    Because without it the deserializer can't possible know which DisplayMode belonging to one of those types the given element relates to.
  • ViRuSTriNiTy
    ViRuSTriNiTy over 7 years
    But why? I don't had a look at the source code of the deserializer but i assume it has the meta info from the classes and the classes each have a property DisplayMode and each property has a type that itself provides also meta info. Therefore everything is available to deserialize it. Hmm perhaps i have to live with that attribute. Very strange...