Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Binary serialization and AssemblyFormat with FormatterAssemblyStyle.Full

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

like image 441
Zivka Avatar asked Jan 15 '23 14:01

Zivka


1 Answers

Documentation on FormatterAssemblyStyle.Full actually says two things:

  1. Assembly.Load method will be used to load the assembly.
  2. Assembly used during deserialization must match exactly the assembly used during serialization.

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.

like image 84
Patko Avatar answered Jan 21 '23 17:01

Patko