.NET Serialization Bug
Here’s a .NET serialization bug that affects both the SoapFormatter and BinaryFormatter:
If you have three or more classes that:
- Are part of the same inheritance hierarchy
- Have the same name but are in different namespaces
- Have a variable that is named the same
Then these objects will not be serialized properly and deserialization will either fail silently or throw an exception.
Example:
Try serializing the class T3.TestClass below using the SoapFormatter:
namespace T1 {
[Serializable]
public class TestClass {
private string myValue = "test";
}
}
namespace T2 {
[Serializable]
public class TestClass : T1.TestClass {
private int myValue = 2;
}
}
namespace T3 {
[Serializable]
public class TestClass : T2.TestClass {
private int myValue = 3;
}
}
What you will get as output is:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:TestClass id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/FutureSource.UndoTestProject.T3/UndoTestProject%2C%20Version%3D1.0.965.20674%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<myValue>3</myValue>
<TestClass_x002B_myValue>2</TestClass_x002B_myValue>
<TestClass_x002B_myValue id="ref-3">test</TestClass_x002B_myValue>
</a1:TestClass>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Notice the two red lines? The variables myValue from classes T1.TestClass and T2.TestClass are improperly mapped to the same name TestClass_x002B_myValue. When the formatter later tries to deserialize this it will wrongly try to assign both the string and the integer to T2.myVaue and fail.
Cause: When three classes that are part of the same hierarchy have a variable that has the same name, the two .NET formatters will keep one name intact when serializing and encode the other two as class name+variable name. Unfortunately, it does not use the full class name (e.g. namespace + class name) when encoding but only the short class name.
Workaround: Write your own serialization surrogate that encodes variable names as variable name+height of declaring class in the hierarchy.