Serializing an object to XML file throws an exception [duplicate] - c#

This question already has answers here:
How to serialize non-static child class of static class
(3 answers)
Closed 7 years ago.
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

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");
}
...
}
}

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

Related

How to serialize & deserialize static reference object?

i want to serialize & deserialize a object (this object has reference) using BinaryFormatter.
i have expected that 'DeserializedObject.Equals(A.Empty)' is same to below code.
but, a result is different.
in order to 'DeserializedObject == A.Empty', how to use serialize/deserialize ?
[Serializable]
public class A
{
private string ID = null;
private string Name = null;
public A()
{ }
public static A Empty = new A()
{
ID = "Empty",
Name = "Empty"
};
}
class Program
{
static void Main(string[] args)
{
A refObject = A.Empty; // Add reference with static object(Empty)
A DeserializedObject;
//Test
//before serialization, refObject and A.Empty is Same!!
if(refObject.Equals(A.Empty))
{
Console.WriteLine("refObject and A.Empty is the same ");
}
//serialization
using (Stream stream = File.Create("C:\\Users\\admin\\Desktop\\test.mbf"))
{
BinaryFormatter bin = new BinaryFormatter();
bin.Serialize(stream, refObject);
}
//Deserialization
using (Stream stream = File.Open("C:\\Users\\admin\\Desktop\\test.mbf", FileMode.Open))
{
BinaryFormatter bin = new BinaryFormatter();
DeserializedObject = (A)bin.Deserialize(stream);
}
//compare DeserializedObject and A.Empty again.
//After deserialization, DeserializedObject and A.Empty is Different!!
if (DeserializedObject.Equals(A.Empty))
{
Console.WriteLine("Same");
}
else
Console.WriteLine("Different");
}
}
The reason for this is that they are different objects! You can check this by printing their GetHashCode(). The reason for this is that in your code:
refObject is a reference to A.Empty (and thus the same object)
DeserialisedObject is NOT a copy; it is a new instance and so a
different object
However DeserializedObject should contain the same values (ID and Name). Note that refObject.ID will be the same object as A.Empty.ID; DeserialisedObject.ID will not, although is should contain (a copy of) the same data.
If you're just testing that deserialization is working, test that the values contained by DeserializedObject and A.Empty are the same.
If you have an immutable type which has one or more global singletons that represent standard values of the type (A.Empty in your case), you can implement the IObjectReference interface and make BinaryFormatter replace deserialized instances of the type with the appropriate, equivalent global singleton. Thus:
[Serializable]
public class A : IObjectReference
{
private string ID = null;
private string Name = null;
public A()
{ }
public static A Empty = new A()
{
ID = "Empty",
Name = "Empty"
};
#region IObjectReference Members
object IObjectReference.GetRealObject(StreamingContext context)
{
if (this.GetType() == Empty.GetType() // Type check because A is not sealed
&& this.ID == Empty.ID
&& this.Name == Empty.Name)
return Empty;
return this;
}
#endregion
}
And, to test:
public class TestClass
{
public static void Test()
{
A refObject = A.Empty; // Add reference with static object(Empty)
Test(refObject, true);
A dummy = new A(); // No global singleton for this one.
Test(dummy, false);
}
private static void Test(A refObject, bool shouldBeEqual)
{
Console.WriteLine(string.Format("refObject and A.Empty are {0}.", object.ReferenceEquals(refObject, A.Empty) ? "identical" : "different"));
var binary = BinaryFormatterHelper.ToBase64String(refObject);
var DeserializedObject = BinaryFormatterHelper.FromBase64String<A>(binary);
Console.WriteLine(string.Format("DeserializedObject and A.Empty are {0}.", object.ReferenceEquals(DeserializedObject, A.Empty) ? "identical" : "different"));
Debug.Assert(object.ReferenceEquals(refObject, A.Empty) == object.ReferenceEquals(DeserializedObject, A.Empty)); // No assert
Debug.Assert(shouldBeEqual == object.ReferenceEquals(refObject, DeserializedObject)); // No assert
}
}
public static class BinaryFormatterHelper
{
public static string ToBase64String<T>(T obj)
{
using (var stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, obj);
return Convert.ToBase64String(stream.GetBuffer(), 0, checked((int)stream.Length)); // Throw an exception on overflow.
}
}
public static T FromBase64String<T>(string data)
{
return FromBase64String<T>(data, null);
}
public static T FromBase64String<T>(string data, BinaryFormatter formatter)
{
using (var stream = new MemoryStream(Convert.FromBase64String(data)))
{
formatter = (formatter ?? new BinaryFormatter());
var obj = formatter.Deserialize(stream);
if (obj is T)
return (T)obj;
return default(T);
}
}
}

Unable to pass Delegation Object across AppDomain in C# due to SerializationException

I am trying to create and pass a Delegate from one AppDomain to another.
But it throws Error only when passing Delegates. If objects like String are passed, it works fine.
Also If the delegate is removed from setting through a constructor and set using a method, I am still unable to pass it to the object.
namespace TESTNS1 {
class Program {
static void Main(string[] args) {
try {
Program obj = new Program();
NS22.testappdom.MYDelT tt = new NS22.testappdom.MYDelT(obj.testingg);
NS22.testappdom obb = new NS22.testappdom(tt);
obb.invokeT();
AppDomain app1 = AppDomain.CreateDomain("newdom");
NS22.testappdom ob2 = (NS22.testappdom)app1.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, typeof(NS22.testappdom).FullName,
false, BindingFlags.Default, null, new object[] { tt }, null, null, null);
ob2.invokeT();
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
public bool testingg (Object obj) {
Console.WriteLine("testingg called..");
return false;
}
}
}
namespace NS22 {
class testappdom : MarshalByRefObject {
public delegate bool MYDelT(Object obj);
public MYDelT delee;
public testappdom() {
Console.WriteLine("Init.");
}
public testappdom(MYDelT dd) {
Console.WriteLine("Init1.");
this.delee = dd;
}
public void invokeT() {
this.delee(new Object());
}
}
}

Token EndElement in state EndRootElement would result in an invalid XML document

I am developing an application for wp7.i am storing the state of my application in isolatedstoragefile using datacontractserializer.Now when i try to serialize the object
sometimes i face this exception.
Token EndElement in state EndRootElement would result in an invalid
XML document. Make sure that the ConformanceLevel setting is set to
ConformanceLevel.Fragment or ConformanceLevel.Auto if you want to
write an XML fragment.
here is my class which i am serializing
[DataContract]
public class TcpSessionProperties
{
[DataMember]
public int NumberOfReceivedStanzas { get { return _numberOfReceivedStanzas; } set { _numberOfReceivedStanzas = value; } }
[DataMember]
public int NumberOfPacketsSent { get { return _numberOfPacketsSent; } set { _numberOfPacketsSent = value; } }
[DataMember]
public List<TcpPacket> PendingPacketsToSendQueue
{
get { return _pendinPacketsToSendQueue; }
set
{
LogUtility.Log(Thread.CurrentThread.GetHashCode());
_pendinPacketsToSendQueue = value;
}
}
}
cla
Here is my code where i am serializing and deserializing
public class AppCacheIsolatedFile
{
public static void Add(object val)
{
private static object _objectToSave;
lock (_storageLock)
{
/*
if (PhoneApplicationService.Current.State.ContainsKey(key))
PhoneApplicationService.Current.State[key] = val;
else
PhoneApplicationService.Current.State.Add(key, val);
*/
_objectToSave = val;
WriteObject(NameOfFile, val, typeof(StreamingSocketConnection.StreamingSocketConnection));
}
public static void WriteObject(string fileName,object val,Type type)
{
try
{
Console.WriteLine(
"Creating a Person object and serializing it.");
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, IsoStore))
{
DataContractSerializer dcs = new DataContractSerializer(type);
dcs.WriteObject(stream, val);
}
}
catch (Exception exception)
{
LogUtility.NotifyUserAndLog("Exception occured in isolatd storage file while writing "+exception.StackTrace);
}
}
}
That exception occurs at dcs.writeobject. I donnot why is this happening.

Why is XmlSerializer throwing an InvalidOperationException?

public void Save() {
XmlSerializer Serializer = new XmlSerializer(typeof(DatabaseInformation));
/*
A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll
A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll
A first chance exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
*/
// ....
}
This is the whole class if you need it:
public class DatabaseInformation
{
/* Create new database */
public DatabaseInformation(string name) {
mName = name;
NeedsSaving = true;
mFieldsInfo = new List<DatabaseField>();
}
/* Read from file */
public static DatabaseInformation DeserializeFromFile(string xml_file_path)
{
XmlSerializer Serializer = new XmlSerializer(typeof(DatabaseInformation));
TextReader r = new StreamReader(xml_file_path);
DatabaseInformation ret = (DatabaseInformation)Serializer.Deserialize(r);
r.Close();
ret.NeedsSaving = false;
return ret;
}
/* Save */
public void Save() {
XmlSerializer Serializer = new XmlSerializer(typeof(DatabaseInformation));
if (!mNeedsSaving)
return;
TextWriter w = new StreamWriter(Path.Combine(Program.MainView.CommonDirectory.Get(), Name + ".xml"), false);
Serializer.Serialize(w, this);
w.Close();
NeedsSaving = false;
}
private string mName;
public string Name { get { return mName; } }
private bool mNeedsSaving;
public bool NeedsSaving { get { return mNeedsSaving; } set { mNeedsSaving = value; Program.MainView.UpdateTitle(value); } }
private bool mHasId;
public bool HasId { get { return mHasId; } }
List<DatabaseField> mFieldsInfo;
}
(PS: if you have any tips to improve my code feel free to share, I'm a C# beginner)
To serialize/deserialize your type it needs to have parameterless constructor. Check out here :
A class must have a default constructor to be serialized by
XmlSerializer.
oh.. I didn't know it had additional information (had to click "View detail.."), mystery solved:
Message=SDB.DatabaseInformation cannot
be serialized because it does not have
a parameterless constructor.
I was also getting this exception, but it wasn't due to missing a default constructor. I had some extra properties (a List and Dictionary) which aren't part of the XML document.
Decorating those properties with [XmlIgnore] solved the problem for me.
You can get around this by providing a default constructor that calls the overloaded constructor. For example:
public DatabaseInformation() : this ("defaultName"){}

How to make second test passing in these C# Xml unit tests? What do I miss in initialization of XmlReaderSettings?

Issue description:
I need to fix an issue with resolving of standard HTML entitities.
I've implemented HtmlEntityReader - implementation of XmlReader which has a code to resolve entities
Public API of our system provides a methods with usage of XmlReader, so user can pass XmlReader created using one of the XmlReader.Create methods
Current code of my xml unit tests is below:
using System.Xml;
using NUnit.Framework;
namespace Tests
{
[TestFixture]
public class XmlTests
{
// this test works
[Test]
public void TestEntitiesResolving1()
{
var path = QA.ResolvePath(#"html\bugs\317.html");
using (var reader = new XmlTextReader(path, new NameTable()))
{
reader.XmlResolver = null; //to prevent DTD downloading
var wrapper = new HtmlEntityReader(reader, XmlUtils.HtmlEntities);
while (wrapper.Read()) { }
}
}
// this test does not work - why?
// what's the difference in initialization of internal XmlTextReaderImpl?
[Test]
public void TestEntitiesResolving2()
{
var path = QA.ResolvePath(#"html\bugs\317.html");
var settings = new XmlReaderSettings
{
XmlResolver = null, //to prevent DTD downloading
NameTable = new NameTable(),
ProhibitDtd = false,
CheckCharacters = false,
};
using (var reader = XmlReader.Create(path, settings))
{
var wrapper = new HtmlEntityReader(reader, XmlUtils.HtmlEntities);
while (wrapper.Read()) { }
}
}
}
}
Partial code of HtmlEntityReader is below:
internal sealed class HtmlEntityReader : XmlReader
{
readonly XmlReader _impl;
readonly Hashtable _entitySet;
string _entityValue;
public HtmlEntityReader(XmlReader reader, Hashtable entitySet)
{
if (reader == null) throw new ArgumentNullException("reader");
if (entitySet == null) throw new ArgumentNullException("entitySet");
_impl = reader;
_entitySet = entitySet;
}
public override XmlNodeType NodeType
{
get { return _entityValue != null ? XmlNodeType.Text : _impl.NodeType; }
}
public override string LocalName
{
get { return _entityValue != null ? string.Empty : _impl.LocalName; }
}
public override string Prefix
{
get { return _entityValue != null ? string.Empty : _impl.Prefix; }
}
public override string Name
{
get { return _entityValue != null ? string.Empty : _impl.Name; }
}
public override bool HasValue
{
get { return _entityValue != null || _impl.HasValue; }
}
public override string Value
{
get { return _entityValue ?? _impl.Value; }
}
public override bool CanResolveEntity
{
get { return true; }
}
public override void ResolveEntity()
{
//it seems this does not call - why?
}
public override bool Read()
{
_entityValue = null;
if (!_impl.Read()) return false;
if (NodeType == XmlNodeType.EntityReference)
{
//resolving of entity reference
_entityValue = (string)_entitySet[Name];
}
return true;
}
// ... delegation of XmlReader abstract methods to _impl
}
I've got the exception:
System.Xml.XmlException: Reference to undeclared entity 'nbsp'. Line 4, position 5.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg, Int32 lineNo, Int32 linePos)
at System.Xml.XmlTextReaderImpl.HandleGeneralEntityReference(String name, Boolean isInAttributeValue, Boolean pushFakeEntityIfNullResolver, Int32 entityStartLinePos)
at System.Xml.XmlTextReaderImpl.HandleEntityReference(Boolean isInAttributeValue, EntityExpandType expandType, ref Int32 charRefEndPos)
at System.Xml.XmlTextReaderImpl.ParseText(ref Int32 startPos, ref Int32 endPos, ref Int32 outOrChars)
at System.Xml.XmlTextReaderImpl.ParseText()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
... private staff
Could you provide a quick advice or link to a solution while I am fixing / investigating / searching this issue through my own efforts?
I've done some research on your question and as best I can tell the only way to ensure that character entities are resolved is to declare them in a DTD. You can resolve the DTD contents yourself (e.g. for caching) by deriving an implementation from the Systm.Xml.XmlResolver base class and responding to GetEntity calls with a stream containing the DTD data.
I wrote an article some time back that explains how to push a default DTD onto the XmlParserContext if there is no DTD declared in your input document. This article is a little dated, but the same concept continues to work with XmlReaderSettings & XmlReader.Create by using an XmlReader.Create overload that accepts an XmlParserContext object as an argument.
Finally, it also looks like .NET 4 will help us out a little with a new XmlResolver derivative named XmlPreloadedResolver which seems to have the XHTML1 and RSS DTDs built in.
The funny thing is that, as sergeyt noted, XmlTextReader doesn't care about undefined entities when processing a xml fragment, while XmlReader does!
So a solution in many cases would be to try with an XmlTextRader.

Categories

Resources