I Summary
II Accident Description
A:B, Please take a look at your service. I have a warning here B: I just released a patch. Is it related to me? A: I haven't released it here. Of course, it matters. Get back! B: I haven't changed the interface you use here. Why should we go back? A: It's my fault. I haven't released anything here. Get back! B: This interface has not been changed for a long time. It must be your own problem. A: No matter who has a problem, let's go back and have a look. B: All right, wait a minute Publishing Assistant: Rolling back... (the alert disappears after rolling back) A:…… B:……
III. Accident analysis
Adding attributes will not cause client deserialization failure.
System.Runtime.Serialization.SerializationException HResult=0x8013150C Message=ObjectManager found an invalid number of link address information. This usually indicates a problem in the formatter. Source=mscorlib StackTrace: In System Runtime.Serialization.ObjectManager.DoFixups() In System Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) In System Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) In System Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
-
The client used for deserialization is too old. Replace the class used for deserialization with the latest class. -
This problem is related to generic collections. If generic collections are added, this problem is likely to occur.
Quad binary serialization and deserialization test
-
Declare classes and attributes in V1; -
In V1, the class objects are binary serialized and saved to a file; -
Modify the attributes of classes in V1, remove the declaration of relevant attributes, and recompile the DLL; -
V2 refers to the DLL generated in step 3, and reads the data generated in step 2 for deserialization; -
/// ///Classes used in V1 testing /// [Serializable] public class ObjectItem { public string TestStr { get; set; } } /// ///V1 Structure used in the test process /// [Serializable] public struct StructItem { public string TestStr; } Results of testing common data types: New Data Type Value for test Whether deserialization is successful int one hundred success int[] {1,100} success string “test” success string[] {“a”,”1″} success double 1d success double[] {1d,2d} success bool true success bool[] {false,true} success List null success List {} success List {“1″,”a”} success List null success List {} success List {1,100} success List null success List {} success List {1d,100d} success List null success List {} success List {true,false} success ObjectItem null success ObjectItem new ObjectItem() success ObjectItem[] {} success ObjectItem{} {new ObjectItem()} Failed (when deserializing, the client does not have the ObjectItem class) ObjectItem{} {new ObjectItem()} Success (when deserializing, the client has the ObjectItem class) List null success List {} success List {new ObjectItem()} Failed (when deserializing, the client does not have the ObjectItem class) List {new ObjectItem()} Success (when deserializing, the client has the ObjectItem class) StructItem null success StructItem new StructItem() success List null success List {} success List {new StructItem()} Success (when deserializing, the client does not have the ObjectItem class) List {new StructItem()} Success (when deserializing, the client has the ObjectItem class) Summary of test results: When the binary system is deserialized, the newly added data of the serializer will be processed automatically and compatibly. However, in some cases, exceptions may occur during deserialization.
Data type with deserialization exception: -
Generic Collection -
array
These two data structures do not necessarily cause binary deserialization errors, but have certain conditions. There are three conditions for deserialization exception of generic collection: -
The serialized object adds a generic collection; -
Generics use new classes; -
The new class does not exist during deserialization;
Arrays are similar. Only when the above three conditions are met will binary deserialization fail. This is why there has been no problem since the previous release, but the microservice client reported an error after the generic collection was assigned. Now that we know through testing that binary deserialization does have an automatic compatible processing mechanism, it is necessary to deeply understand the theoretical knowledge of the fault tolerance mechanism of binary deserialization on MSDN. Fault Tolerant Mechanism of Five Binary Deserialization In the process of binary deserialization, it is inevitable to encounter the situation that the version of the assembly used for serialization and deserialization is different. If the deserializer (such as the client of the microservice) is forced to keep consistent with the serializer (such as the server of the microservice) at all times, it is unrealistic in the actual application process. From NET 2.0 NET introduces Version Tolerance Serialization (VTS) for binary deserialization. When using BinaryFormatter, the VTS function will be enabled. The VTS function is especially enabled for classes (including generic types) that apply the SerializableAttribute attribute. VTS allows you to add new fields to these classes without breaking compatibility with other versions of the type. If the client and server assemblies are different during serialization and deserialization NET will try its best to be compatible, so there is little feeling about it in the normal use process, and even a sense of being used to it. To ensure correct version management behavior, please follow the following rules when modifying type versions: -
Do not remove serialized fields. -
If you did not apply the NonSerializedAttribute attribute to a field in a previous version, do not apply the attribute to that field. -
Do not change the name or type of a serialized field. -
When adding a new serialized field, apply the OptionalFieldAttribute attribute. -
When removing the NonSerializedAttribute attribute from a field that was not serializable in previous versions, apply the OptionalFieldAttribute attribute. -
For all optional fields, unless 0 or null can be accepted as the default value, use the serialization callback to set a meaningful default value.
To ensure that types are compatible with future serialization engines, follow these guidelines: -
The VersionAdded property on the OptionalFieldAttribute attribute is always set correctly. -
Avoid versioning branches.
-
Structure of six binary serialized data
6.1 Data sent during remote call
0000 00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00 ..... ÿÿÿÿ....... 0010 00 15 14 00 00 00 12 0B 53 65 6E 64 41 64 64 72 ........ SendAddr 0020 65 73 73 12 6F 44 4F 4A 52 65 6D 6F 74 69 6E 67 ess.oDOJRemoting 0030 4D 65 74 61 64 61 74 61 2E 4D 79 53 65 72 76 65 Metadata. MyServe 0040 72 2C 20 44 4F 4A 52 65 6D 6F 74 69 6E 67 4D 65 r, DOJRemotingMe 0050 74 61 64 61 74 61 2C 20 56 65 72 73 69 6F 6E 3D tadata, Version= 0060 31 2E 30 2E 32 36 32 32 2E 33 31 33 32 36 2C 20 1.0.2622.31326, 0070 43 75 6C 74 75 72 65 3D 6E 65 75 74 72 61 6C 2C Culture=neutral, 0080 20 50 75 62 6C 69 63 4B 65 79 54 6F 6B 65 6E 3D PublicKeyToken= 0090 6E 75 6C 6C 10 01 00 00 00 01 00 00 00 09 02 00 null............ 00A0 00 00 0C 03 00 00 00 51 44 4F 4A 52 65 6D 6F 74 ....... QDOJRemot 00B0 69 6E 67 4D 65 74 61 64 61 74 61 2C 20 56 65 72 ingMetadata, Ver 00C0 73 69 6F 6E 3D 31 2E 30 2E 32 36 32 32 2E 33 31 sion=1.0.2622.31 00D0 33 32 36 2C 20 43 75 6C 74 75 72 65 3D 6E 65 75 326, Culture=neu 00E0 74 72 61 6C 2C 20 50 75 62 6C 69 63 4B 65 79 54 tral, PublicKeyT 00F0 6F 6B 65 6E 3D 6E 75 6C 6C 05 02 00 00 00 1B 44 oken=null...... D 0100 4F 4A 52 65 6D 6F 74 69 6E 67 4D 65 74 61 64 61 OJRemotingMetada 0110 74 61 2E 41 64 64 72 65 73 73 04 00 00 00 06 53 ta. Address.....S 0120 74 72 65 65 74 04 43 69 74 79 05 53 74 61 74 65 treet. City.State 0130 03 5A 69 70 01 01 01 01 03 00 00 00 06 04 00 00 . Zip............ 0140 00 11 4F 6E 65 20 4D 69 63 72 6F 73 6F 66 74 20 .. One Microsoft 0150 57 61 79 06 05 00 00 00 07 52 65 64 6D 6F 6E 64 Way...... Redmond 0160 06 06 00 00 00 02 57 41 06 07 00 00 00 05 39 38 ...... WA......98 0170 30 35 34 0B 054.
6.2 Binary Serialization Results of Class Objects
/// ///Custom serialized object /// [Serializable] public class MyObject { public bool BoolMember { get; set; } public int IntMember { get; set; } } /// ///Program entry /// class Program { static void Main(string[] args) { var obj = new MyObject(); obj.BoolMember = true; obj.IntMember = 10000; IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream("data.dat", FileMode.Create, FileAccess.Write, FileShare.None); formatter.Serialize(stream, obj); stream.Close(); } }
0000: 00 01 00 00 00 ff ff ff ff 01 00 00 00 00 00 00 ................ 0010: 00 0c 02 00 00 00 4e 42 69 6e 61 72 79 53 65 72 ...... NBinarySer 0020: 69 61 6c 69 7a 65 50 72 61 63 74 69 73 65 2c 20 ializePractise, 0030: 56 65 72 73 69 6f 6e 3d 31 2e 30 2e 30 2e 30 2c Version=1.0.0.0, 0040: 20 43 75 6c 74 75 72 65 3d 6e 65 75 74 72 61 6c Culture=neutral 0050: 2c 20 50 75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e , PublicKeyToken 0060: 3d 6e 75 6c 6c 05 01 00 00 00 20 42 69 6e 61 72 =null..... Binar 0070: 79 53 65 72 69 61 6c 69 7a 65 50 72 61 63 74 69 ySerializePracti 0080: 73 65 2e 4d 79 4f 62 6a 65 63 74 02 00 00 00 1b se.MyObject..... 0090: 3c 42 6f 6f 6c 4d 65 6d 62 65 72 3e 6b 5f 5f 42 k__B 00a0: 61 63 6b 69 6e 67 46 69 65 6c 64 1a 3c 49 6e 74 ackingField.k__Backin 00c0: 67 46 69 65 6c 64 00 00 01 08 02 00 00 00 01 10 gField.......... 00d0: 27 00 00 0b '...
Binary Serialization Format SerializationHeaderRecord: RecordTypeEnum: SerializedStreamHeader (0x00) TopId: 1 (0x1) HeaderId: -1 (0xFFFFFFFF) MajorVersion: 1 (0x1) MinorVersion: 0 (0x0) Record Definition: RecordTypeEnum: SystemClassWithMembers (0x02) ClassInfo: ObjectId: (0x4e000000) LengthPrefixedString: Length: 78 (0x4e) String: BinarySerializePractise, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null ObjectId: (0x00000001) LengthPrefixedString: Length: 32 (0x20) String: BinarySerializePractise.MyObject MemberCount: 2(0x00000002) LengthPrefixedString: Length: 27(0x1b) String: k__BackingField LengthPrefixedString: Length: 26(0x1a) String: k__BackingField ObjectId:0x08010000 Length:0x00000002 Value:1(0x01) Value:10000(0x00002710) MessageEnd: RecordTypeEnum: MessageEnd (0x0b)
VII Summary
VIII Reference materials
-
Some gotchas in backward compatibility -
Version fault-tolerant serialization -
[MS-NRBF]: . NET Remoting: Binary Format Data Structure -
[MS-NRBF]: 3 Structure Examples