4

I've looked in several questions but none of the answers helped. I tried using several stream objects (StreamWriter, FileStream). I tried using XmlWriter, XmlSerializer and more.

This is my code:

namespace FacebookPlusPlus
{
    internal static class AppConfig
    {
        public static string AccessToken
        {
            get { return s_SerializableConfig.m_AccessToken; }
            set { s_SerializableConfig.m_AccessToken = value; }
        }

        public static bool AutoConnect
        {
            get { return s_SerializableConfig.m_AutoConnect; }
            set { s_SerializableConfig.m_AutoConnect = value; }
        }

        public static string ErrorMessage { get; set; }

        private const string k_ConfigFilePath = "AppConfig.xml";
        private static SerializableConfig s_SerializableConfig = new SerializableConfig();

        [Serializable]
        public class SerializableConfig
        {
            public string m_AccessToken;
            public bool m_AutoConnect;
        }

        public static bool ExportConfig()
        {
            bool exportSucceed = false;
            try
            {
                using (StreamWriter writer = new StreamWriter(File.Open(k_ConfigFilePath, FileMode.Create)))
                {
                    XmlSerializer serializer = new XmlSerializer(s_SerializableConfig.GetType());
                    serializer.Serialize(writer, s_SerializableConfig);
                }

                exportSucceed = true;
            }
            catch (Exception exception)
            {
                ErrorMessage = exception.Message;
                if (File.Exists(k_ConfigFilePath))
                {
                    File.Delete(k_ConfigFilePath);
                }
            }

            return exportSucceed;
        }

        public static bool ImportConfig()
        {
            bool importSucceed = false;
            if (File.Exists(k_ConfigFilePath))
            {
                try
                {
                    using (Stream stream = File.Open(k_ConfigFilePath, FileMode.Open))
                    {
                        XmlSerializer serializer = new XmlSerializer(s_SerializableConfig.GetType());
                        s_SerializableConfig = (SerializableConfig)serializer.Deserialize(stream);
                    }

                    importSucceed = true;
                }
                catch (Exception exception)
                {
                    importSucceed = false;
                    ErrorMessage = exception.Message;
                }
            }

            return importSucceed;
        }
    }
}

This is the exception:

There was an error generating the XML document.
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
   at FacebookPlusPlus.AppConfig.ExportConfig() in c:\\...\\AppLogic\\AppConfig.cs:line 48

At the time of error the field AccessToken contained a long string and AutoConnect contained true

Doron Cohen
  • 1,026
  • 8
  • 13
  • 1
    Can you check for any `InnerException` errors that are in the thrown exception as well? With `XmlSerializer`, those inner exceptions usually contain relevant information. – Chris Sinclair Aug 13 '15 at 19:37
  • 2
    This is a known bug/"limitation" of `XmlSerializer`. See [How to serialize non-static child class of static class](http://stackoverflow.com/questions/4479817/how-to-serialize-non-static-child-class-of-static-class). Workarounds are to un-nest the nested class or use `DataContractSerializer`, or make the outer class non-static but with a private constructor that throws an exception. – dbc Aug 13 '15 at 20:33
  • @dbc, thanks. see my answer – Doron Cohen Aug 13 '15 at 21:12

2 Answers2

1

OK, I did what @dbc suggested and made AppConfig public, removed its static attribute and concealed its c'tor. Works great!

Still am frustrated about C# weird limitations, this took me a couple of hours to understand. And I hate workarounds

namespace FacebookPlusPlus
{
    public class AppConfig
    {
        ...

        [Serializable]
        public class SerializableConfig
        {
            public string m_AccessToken;
            public bool m_AutoConnect;
        }

        private AppConfig() 
        {
            throw new InvalidOperationException("AppConfig Ctor Invoked");
        }

        ...
    }
}
Doron Cohen
  • 1,026
  • 8
  • 13
0

When you call the Serealize method, the first parameter you are specifying may be the root cause of the issue:

In the xmlWriter parameter, specify an object that derives from the abstract XmlWriter class. The XmlTextWriter derives from the XmlWriter.

In your case, you are using StreamWriter which is not an XmlWriter.

Source: https://msdn.microsoft.com/en-us/library/10y9yyta(v=VS.110).aspx

Edit: Since you have already tried the above and it did not help with your problem, like Chris Sinclair said, try getting the inner exception. The following code snippet could help:

public void SerializeContainer( XmlWriter writer, Container obj )
{
  try
  {
    // Make sure even the construsctor runs inside a
    // try-catch block
    XmlSerializer ser = new XmlSerializer( typeof(Container));
    ser.Serialize( writer, obj );
  }
  catch( Exception ex )               
  {                                   
    DumpException( ex );             
  }                                   
}
public static void DumpException( Exception ex )
{
  Console.WriteLine( "--------- Outer Exception Data ---------" );        
  WriteExceptionInfo( ex );
  ex = ex.InnerException;                     
  if( null != ex )               
  {                                   
    Console.WriteLine( "--------- Inner Exception Data ---------" );                
    WriteExceptionInfo( ex.InnerException );    
    ex = ex.InnerException;
  }
}
public static void WriteExceptionInfo( Exception ex )
{
  Console.WriteLine( "Message: {0}", ex.Message );                  
  Console.WriteLine( "Exception Type: {0}", ex.GetType().FullName );
  Console.WriteLine( "Source: {0}", ex.Source );                    
  Console.WriteLine( "StrackTrace: {0}", ex.StackTrace );           
  Console.WriteLine( "TargetSite: {0}", ex.TargetSite );            
}

Source: https://msdn.microsoft.com/en-us/library/Aa302290.aspx

gmalla
  • 21
  • 4
  • 1
    They indicated they tried `XmlWriter` and it didn't work. Furthermore, `StreamWriter` is a valid input as it inherits from `TextWriter` which works with [this overload of `Serialize`.](https://msdn.microsoft.com/en-us/library/d15aekdk%28v=vs.110%29.aspx) – Chris Sinclair Aug 13 '15 at 19:42
  • Oops. They did mention that right at the beginning. – gmalla Aug 13 '15 at 19:45
  • Yes, I did try that. Why is it so hard to serialize an object to XML anyway? it seems .NET should be in the right mood just to allow you to convert some data to strings. – Doron Cohen Aug 13 '15 at 19:56
  • 1
    thanks @gmalla, solved it. – Doron Cohen Aug 13 '15 at 21:12