Archive for the ‘Serialization’ Category
Use XML attributes to specify a unique XML name and/or namespace for the type.
The following error
Types ‘NameSpace1.MyClass’ and NameSpace2.MyClass’ both use the XML type name, ‘MyClass’, from namespace XMLNameSpace’. Use XML attributes to specify a unique XML name and/or namespace for the type.
happens because there is a major difference between .net namespaces and the xml namespaces. The serializer does not pick up .net namespaces and gets confused by seeing the same class in two different namespaces. To resolve the error add the following attribute to both classes
[System.Xml.Serialization.XmlRoot(Namespace = "NameSpace1")] and [System.Xml.Serialization.XmlRoot(Namespace = "NameSpace2")] this way the .net namespace and the xml namespace are in sync.
XML – Binary – JSon Serialization
It appears that there are more than one way to skin a cat and sometimes it tough to decide on how to skin a cat. With serialization there are three common ways to serialize an object each has there advantages and disadvantages.
XML Serialization
XML serialization allows you to exchange data between disjoint systems e.g. C# and PHP. The downside of XML serialization is that it is very verbose and out of the box C# does not support serialization of a dicationary.
Example of XML Serialization
using System.Xml.Serialization; StreamWriter _XMLOut = new StreamWriter(_filepath); XmlSerializer _ProjectSerializer = new XmlSerializer(typeof(MyObject)); _ProjectSerializer.Serialize(_XMLOut, _MyObject); _XMLOut.Close();
Example of XML Deserialization
using System.Xml.Serialization; StreamReader _XMLIn = new StreamReader(_filepath); XmlSerializer _ProjectSerializer = new XmlSerializer(typeof(MyObject)); _MyObject = (MyObject)_ProjectSerializer.Deserialize(_XMLIn); _XMLOut.Close();
Binary Serialization
Binary serialization is less verbose and does support serialization of dicationaries however you can not exchange binary serialized messages between disjoint systems.
Example of Binary Serialization
using System.Runtime.Serialization.Formatters.Binary; FileStream _stream = new FileStream(_filepath, FileMode.CreateNew); BinaryFormatter _Formatter = new BinaryFormatter(); _Formatter.Serialize(_stream, _MyObject); stream.Close();
Example of Binary Deserialization
using System.Runtime.Serialization.Formatters.Binary; FileStream _stream = new FileStream(_filepath, FileMode.Open); BinaryFormatter _Formatter = new BinaryFormatter(); _MyObject = (MyObject)objFormatter.Deserialize(_stream);
JSon Serialization
JSon serialization is less verbose allows for seriaization of dictionaries and can be used to exchange messages between disjoint systems the downfall of JSon is that the serialized information contains no type definitions.
Example of JSON Serialization
using System.Runtime.Serialization.Json; DataContractJsonSerializer _Serializer = new DataContractJsonSerializer(_MyObject.GetType()); MemoryStream _DataMemoryStream = new MemoryStream(); _Serializer.WriteObject(_DataMemoryStream , _MyObject);
Example of JSON Deserialization
using System.Runtime.Serialization.Json; MemoryStream _MemoryStream = new MemoryStream(_DataStream); DataContractJsonSerializer _Deserializer = new DataContractJsonSerializer(_MyObject.GetType()); return (MyObject)_Deserializer.ReadObject(_MemoryStream);
One major negative aspect JSON serialization is that you need the same version of the object to serialize and deserialize it. The deserializer will fail if the newer version of the object as an additional property.
Dicationary Serialization
Back to serialization again this is a beast that just wont die every time I think I know everything about serialization that there is to know about I get whacked over the head with it. One of the big issues with xml serialization is that it will not serialize a dictionary if you try you get an error like this
Cannot serialize member SSD.SourceControl.Modules.Files.Monitors.Business.MonitorSettings.Accesses of type System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], because it implements IDictionary.
You have four ways to deal with this
- Do not use a dictionary
- Override the dictionary and implement IXmlSerializable (http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx)
- Use binary serialization
- Use JSON Serialization
Personally my preference is to either user binary serialization or JSON serialization if that is an option.
Serialization
Having just recently ran into some major serialization issues I’m going to list some of the errors and pitfalls that I ran into.
Some of the errors encountered
Error one
“<ClassName> is inaccessible due to its protection level. Only public types can be processed.”
It means that the Class you are trying to serialize is not marked as public and hence the serializor can not access it. Depending on the Class scope this may not be a problem e.g. the serialization code and the class are both in the same scope.
Error Two
“Cannot serialize member <Property Name> of type <Type> because it is an interface.”
It means that one of the members in your class is defined as an interface. An interface can never be serialized since the serializor will not know which instance of the interface to use.
Error Three
The type <Type> was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
This error is caused when trying to serialize an inherited class
E.g. the following example will cause this problem
public class Test
{
private string _Field = "";
public string Field
{
get { return _Field; }
set { _Field = value; }
}
}
public class TestInherited : Test
{
}
public class Container
{
private Test ivField;
public Test Field
{
get { return _Field; }
set { _Field = value; }
}
}
Container _Test = new Container();
_Test.Field = new TestInherited();
The issue is that the Container.Field is defined as Test but instantiated as TestInherited. Their are two solutions for this problem
1) Add the attribute [XmlInclude(typeof(TestInherited))] to the Test class
2) new XmlSerializer(typeof(Container), new Type[] { typeof(TestInherited) });
The second method is preferred. With the first method you have to decorate your base classes to which you may not always have access to, secondly the base class should not be aware of any class that inherits from it.