XML Serialization Error - There was an error reflecting type

13,879

OK. I just encountered this. And solved it using a wrapper object.

What I did was to create a simple wrapper object for the thing I want to serialize. I my case it is a ConfigurationCollection. I serialize that and create a couple adapters to map from the serializable object to the actual object and vice versa.

using system.Xml.Serialization;

// This is an XML wrapper for FolderElement.
public class FolderAttributes
{
    [XmlAttribute("Name")]
    public string Name { get; set; }
    [XmlAttribute("Volume")]
    public string Volume { get; set; }
    [XmlAttribute("Path")]
    public string Path { get; set; }

    [XmlAttribute("Selected")]
    public bool Selected { get; set; }
    [XmlAttribute("Active")]
    public bool Active { get; set; }

    /// <summary>
    /// Factory Method.
    /// Create new instance of FolderAttributes from FolderElment.
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    public static FolderAttributes FromElement(FolderElement element)
    {
        return new FolderAttributes()
        {
            Name = element.Name,
            Volume = element.VolumeLabel,
            Path = element.Path,
            Selected = element.Selected,
            Active = element.Active
        };

    }

    /// <summary>
    /// Convert this instance to a FolderElement.
    /// </summary>
    /// <returns></returns>
    public FolderElement ToElement()
    {
        return new FolderElement()
        {
            Name = Name,
            VolumeLabel = Volume,
            Path = Path,
            Selected = Selected,
            Active = Active
        };

    }
}
public class FolderElement : ConfigurationElement
{
    protected const string NameKey = "name";
    protected const string VolumeKey = "volume";
    protected const string PathKey = "path";
    protected const string selectedKey = "selected";
    protected const string activeKey = "active";

    [ConfigurationProperty(NameKey, DefaultValue = "", IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)base[NameKey]; }
        set { base[NameKey] = value; }
    }

    [ConfigurationProperty(VolumeKey, DefaultValue = "", IsKey = false, IsRequired = false)]
    public string VolumeLabel
    {
        get { return (string)base[VolumeKey]; }
        set { base[VolumeKey] = value; }
    }

    [ConfigurationProperty(PathKey, DefaultValue = "", IsKey = false, IsRequired = true)]
    public string Path
    {
        get { return (string)base[PathKey]; }
        set { base[PathKey] = value; }
    }

    [ConfigurationProperty(selectedKey, DefaultValue = "false", IsKey = false, IsRequired = false)]
    public bool Selected
    {
        get { return (bool)base[selectedKey]; }
        set { base[selectedKey] = value; }
    }

    [ConfigurationProperty(activeKey, DefaultValue = "true", IsKey = false, IsRequired = false)]
    public bool Active
    {
        get { return (bool)base[activeKey]; }
        set { base[activeKey] = value; }
    }
}

[ConfigurationCollection(typeof(FolderElement))]
public class FolderCollection : ConfigurationElementCollection
{
    internal const string _elementName = "elements";

    protected override string ElementName
    {
        get { return _elementName; }
    }

    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
    }

    protected override bool IsElementName(string elementName)
    {
        return elementName.Equals(_elementName, StringComparison.InvariantCultureIgnoreCase);
    }

    public override bool IsReadOnly()
    {
        return false;
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new FolderElement();
    }

    /// <summary>
    /// Return key value for element.
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((FolderElement)element).Name;
    }

    /// <summary>
    /// Default index property.
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public FolderElement this[int index]
    {
        get { return (FolderElement)BaseGet(index); }
    }


    /// <summary>
    /// Returns content element by name.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public FolderElement GetElementByName(string name)
    {
        return (FolderElement)BaseGet(name);
    }


    public IEnumerable<FolderElement> Elements
    {
        get
        {
            for (int index = 0; index < this.Count; index++) yield return (FolderElement)BaseGet(index);
        }
    }

    /// <summary>
    /// Add an element to the collection
    /// </summary>
    /// <param name="element"></param>
    public void AddElement(FolderElement element)
    {
        BaseAdd(element);
    }


}

public class FolderSection : ConfigurationSection
{

    // Attribute argument must be a constant expression.
    protected const string _elementsTag = "elements";

    [ConfigurationProperty(_elementsTag, Options = ConfigurationPropertyOptions.IsDefaultCollection)]
    public FolderCollection Elements
    {
        get { return ((FolderCollection)(base[_elementsTag])); }
        set { base[_elementsTag] = value; }
    }

    public void SaveElements(ConfigurationElementCollection elements, string path)
    {
        var container = new List<FolderAttributes>();

        foreach (FolderElement element in elements)
        {
            container.Add(FolderAttributes.FromElement(element));
        }

        // XmlHelper.SaveXml(container, path);
        SaveXml(container, path);

    }

    /// <summary>
    /// Load elements from xml file pointed to by path.
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public List<FolderElement> LoadElements(string path)
    {
        List<FolderElement> result = new List<FolderElement>();

        var attributes = Deserialize<List<FolderAttributes>>(path);
        if (attributes != null)
        {
            foreach (var attr in attributes)
            {
                var element = attr.ToElement();
                result.Add(element);
            }
        }

        return result;
    }

    /// <summary>
    /// Save XML serialization of object to named file.
    /// </summary>
    /// <param name="value"></param>
    /// <param name="fileName"></param>
    public static void SaveXml(Object value, string fileName)
    {
        // First serialize the object to memory stream,
        // in case of exception, the original file is not corrupted
        using (MemoryStream ms = new MemoryStream())
        {
            var stream = new System.IO.StreamWriter(ms);
            if (Serialize(value, stream))
            {
                // if the serialization succeeded, rewrite the file.
                File.WriteAllBytes(fileName, ms.ToArray());
            }
        }

    }

    /// <summary>
    /// Base-level method to serialize object to TextWriter.
    /// </summary>
    /// <param name="value"></param>
    /// <param name="output"></param>
    /// <returns></returns>
    public static bool Serialize<T>(object value, TextWriter output)
    {
        if (value == null) throw new ArgumentNullException("Serialize(value)");

        bool result = false;
        Type T = value.GetType();

        try
        {
            var xmlSerializer = new XmlSerializer(typeof(T));
            using (var xmlWriter = XmlWriter.Create(output, new XmlWriterSettings { Indent = true }))
            {
                xmlSerializer.Serialize(xmlWriter, value);
                result = true;
            }
        }
        catch (Exception)
        {
            // Log.Error(ex, "WriteXml {0}", T.Name);
        }

        return result;
    }

    public static T Deserialize<T>(string fileName)
    {
        T result = default(T);
        try
        {
            using (var stream = System.IO.File.OpenRead(fileName))
            {
                var serializer = new XmlSerializer(typeof(T));
                result = (T)serializer.Deserialize(stream);
            }
        }
        catch (Exception)
        {
            // Log.Error(ex, "Deserialize<{0}> from file {1}", typeof(T).Name, fileName);
        }
        return result;
    }

}
Share:
13,879
Saroj
Author by

Saroj

Updated on June 04, 2022

Comments

  • Saroj
    Saroj almost 2 years

    I am trying to serialize few custom settings from configuration file. Below are my settings:

    <FavouriteTools>
            <favouriteTool PluginPlaceHolder="FavoriteTool1" PlugInName="Brightness"
              PlugInType="2D" PlugInAssemblyName="Micro.DigiMic.Plugins.AreaBasedOnBrightness.AreaBasedOnBrightnessPlugin"
              GUID="0000c03a-b891-4ebd-87d7-5fbc19073a1a" />
            <favouriteTool PluginPlaceHolder="FavoriteTool2" PlugInName="CircleArea"
              PlugInType="2D" PlugInAssemblyName="Micro.DigiMic.Plugins.CircleAreaPlugin.CircleAreaPlugin"
              GUID="0000c06a-b891-4ebd-87d7-5fbc19073a1a" />
            <favouriteTool PluginPlaceHolder="FavoriteTool3" PlugInName="Contour Area"
              PlugInType="2D" PlugInAssemblyName="Micro.DigiMic.Plugins.ContourAreaPlugin.ContourAreaPlugin"
              GUID="0000c11a-b891-4ebd-87d7-5fbc19073a1a" />         
    

    But I get error during serializing them. Here are my classes.

    //FavouriteTools - Root Node
    [Serializable]
    [XmlType("FavoriteTools")]
    [ConfigurationCollection(typeof(FavouriteTool), AddItemName = "favouriteTool", CollectionType = ConfigurationElementCollectionType.BasicMap)]
    public class FavouriteToolsCollection
    : ConfigurationElementCollection    
    {
    //Few plublic methods here
    }
    
    //favouriteTool -  Child node
    [Serializable]
    [XmlType("favouriteTool")]
    public class FavouriteTool : ConfigurationElement
    {
        /// <summary>
        /// Gets or sets value of Plugin PlaceHolder.
        /// </summary>
        /// <value>Text Color.</value> 
        [ConfigurationProperty("PluginPlaceHolder", IsRequired = false)]
        public string PlugPlaceHolder
        {
            get { return (string)base["PluginPlaceHolder"]; }
            set { base["PluginPlaceHolder"] = value; }
        }
    
    //Few more properties like above
    }
    
    I am trying to serialize below class, but gets exception on below like
    
    XmlSerializer xmlinf = new XmlSerializer(data.GetType());
    
    
    `data` is `ExportUser`
    
    [Serializable]
    public class ExportUser
    {
    
    public bool IsMetric { get; set; }
    
    [XmlArray("FavoriteTools")]
        [XmlArrayItem("favouriteTool")]
        public FavouriteToolsCollection FavoriteTools { get; set; }
     }  
    

    I get this error - There was an error reflecting type 'ExportUser' and in inner exception the error says - There was an error reflecting type 'FavoriteTools'.

    Is there anything missing?

    Update:

    After seeing the inner exception, the error is

    {"You must implement a default accessor on System.Configuration.ConfigurationLockCollection because it inherits from ICollection."}

    There was an error reflecting type 'Zeiss.Micro.DigiMic.Application.FavouriteTool'.

    But I do have a default accessor in FavouriteToolsCollection class:

    public FavouriteTool this[int index]
        {
            get
            {
                return (FavouriteTool)BaseGet(index);
            }
    
            set
            {
                if (this.BaseGet(index) != null)
                {
                    this.BaseRemoveAt(index);
                }
    
                this.BaseAdd(index, value);
            }
        }
    

    What more is missing?

    • Marc Gravell
      Marc Gravell over 10 years
      What was the inner exception of the inner exception? (etc) - it actually gives really detailed messages if you keep drilling. Btw - did it actually say ...reflecting type 'FavoriteTools'? because in the code: that isn't a type
    • Saroj
      Saroj over 10 years
      @MarcGravell - For non-array types, you may use the following attributes: XmlAttribute, XmlText, XmlElement, or XmlAnyElement. - Here is the exact message with innerException There was an error reflecting type 'FavoriteTools'