I am curious to know how to "break" deserialization using the assembly format of the binary formatter with FormatterAssemblyStyle.Full.
The documentation states for this:
In full mode, the assembly used during deserialization must match exactly the assembly used during serialization.
I thought that if I serialize an object (_person which is a simple class with value type fields) with version 1.0.0.0 of the assembly, then try deserialize with v1.2.0.0 (updating the AssemblyInfo.cs) of the assembly, I would get a deserialization exception. However, it deserializes successfully.
Am I missing something?
I am serializing to file using the following:
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full;
using (Stream stream = new FileStream(fileName,
FileMode.Create,
FileAccess.Write,
FileShare.None))
{
formatter.Serialize(stream, _person);
stream.Close();
}
and then deserializing using the following:
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full;
using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
_person = (Person)formatter.Deserialize(stream);
stream.Close();
}
I've also noticed that the serialized file produced using FormatterAssemblyStyle.Full and FormatterAssemblyStyle.Simple both contain the complete version info (e.g. Version 1.0.0.0 Culture = neutral, PublicKeyToken = null) - I thought that Simple would not add all this information? (see formatters and assembly names section from this)
Update 1:
The only difference I have seen so far is, if I use Simple, then I don't have to place the OptionalField
attribute to new fields in a serialized class for it to de-serialize old versions successfully. If I use Full, then it does throw an exception unless I place the OptionalField
attribute on new fields. Is this the only difference if using assemblies which are not strong named??
See this for details.
Thanks in advance
Documentation on FormatterAssemblyStyle.Full
actually says two things:
Assembly loading via Assembly.Load
When the assembly is loaded the assembly version is also checked, but only if assembly is strongly named. Docs on Assembly Versioning say this:
The runtime distinguishes between regular and strong-named assemblies for the purposes of versioning. Version checking only occurs with strong-named assemblies.
To strongly name the assembly just follow the steps in How to: Sign an Assembly with a Strong Name. Also, even if you specify the fully qualified assembly name for an assembly without strong name, AssemblyName docs state the following:
When supplying a display name, the convention StrongName =null or PublicKey= null indicates that binding and matching against a simply named assembly is required.
So even if using Assembly.Load
method the runtime will always load regular assemblies without a version check.
Full Deserialization
It is not exactly true that the whole assembly must match the assembly used during deserialization. Only the class (and all other classes in object graph) which is being deserialized should match. In each deserialized class only the fields should match, you can add new methods at will. Version Tolerant Serialization covers this in more detail.
To sum it up, yes, if you do not have strongly named assemblies then the only difference is in how tolerant deserialization is. So either you use Full
deserialization with OptionalFieldAttribute
or Simple
deserialization, depending on your context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With