Bug 30354 - Unexpected binary element 9 when deserializing CookieContainer with BinaryFormatter
Summary: Unexpected binary element 9 when deserializing CookieContainer with BinaryFor...
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: XI 8.10
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2015-05-22 11:31 UTC by John Miller [MSFT]
Modified: 2015-05-25 09:32 UTC (History)
4 users (show)

Is this bug a regression?: ---
Last known good build:

Test Case (8.30 KB, application/zip)
2015-05-22 11:31 UTC, John Miller [MSFT]

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description John Miller [MSFT] 2015-05-22 11:31:05 UTC
Created attachment 11299 [details]
Test Case


   After updating to XI 8.10 from 8.8, deserializing CookieContainer fails with an exception. 

**Steps to Reproduce:**

   1. Install XI
   2. Run the attached sample on a simulator. An alert will show a success.
   3. Kill, and run the app again on the simulator. Another alert will show that the cookie was loaded.
   4. Install XI 8.10+
   5. Run the app again.

**Actual Results:**

   Unexpected binary element: 9 (System.Runtime.Serialization.SerializationException)
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00189] in /Users/builder/data/lanes/1799/3c4e832a/source/mono/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:250 
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (System.IO.BinaryReader reader) [0x00027] in /Users/builder/data/lanes/1799/3c4e832a/source/mono/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:150 
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers) [0x0004d] in /Users/builder/data/lanes/1799/3c4e832a/source/mono/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:107 
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) [0x0007a] in /Users/builder/data/lanes/1799/3c4e832a/source/mono/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:177 
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) [0x00000] in /Users/builder/data/lanes/1799/3c4e832a/source/mono/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryFormatter.cs:134 
  at CookieTest.AppDelegate.FinishedLaunching (UIKit.UIApplication application, Foundation.NSDictionary launchOptions) [0x0002f] in /Users/johnmiller/Downloads/CookieTest/AppDelegate.cs:42 
  at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/1799/3c4e832a/source/maccore/src/UIKit/UIApplication.cs:63 
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/1799/3c4e832a/source/maccore/src/UIKit/UIApplication.cs:47 
  at CookieTest.Application.Main (System.String[] args) [0x00008] in /Users/johnmiller/Downloads/CookieTest/Main.cs:12 

**Expected Results:**

   No exceptions. The same alert from step #3 should work. 

**Build Date & Platform:**

   XI 8.10

**Additional Information:**

   Maybe something changed in the serialization/CookieContainer between the XI versions
Comment 1 Sebastien Pouliot 2015-05-23 10:16:41 UTC
XI 8.8 was based on Mono 3.12
XI 8.10 was based on Mono 4.0

Mono 4.0 includes quite a bit of Microsoft's .NET reference sources [1] in it's class libraries which, in turn, is used for what XI (and other Xamarin products) ships.

That's good news for compatibility with MS .NET but it also means some internals do change (it's the only way to gain that increased compatibility). 

In this case the (undocumented) internals of CookieContainer changed and that broke the binary serialization of that type.

A strategy to workaround this would be to have the application:
1. load the serialized data;
2. catch the exception, if there's any
2.1 re-create the data and re-serialize it with the new format
3. continue execution

Alternatively use another mechanism to serialize your data, one that does not depend on the internals of the types.

[1] work in progress, but CookieContainer was done in 4.0 mcs/class/System/System.dll.sources:../../../external/referencesource/System/net/System/Net/cookiecontainer.cs
Comment 2 Brad Robinson 2015-05-24 19:13:20 UTC
Hi Sebastien,

Thanks for looking into this.  Pretty much what I expected.  Unfortunately the suggested strategy has some problems:

1. An exception is not always thrown when loading the data.  Sometimes it throws an exception, sometimes it loads but causes a later exception when accessing the cookie container and sometimes it loads but ends up empty.
2. Re-creating the data is not necessarily as simple as implied.  In our case we're storing a login cookie from our server.  To recreate that requires the user to login again - not a good user experience and may require unwinding the user-interface stack.
3. It makes no guarantees that we're not going to be bitten by this again - which makes the whole point of a serializable cookie container pointless.
4. I'd like to build my own serialization of CookieContainer but it's contents can't be enumerated - making that impossible.
5. The Cookie class can't be fully serialized externally because it has read-only properties (TimeStamp comes to mind) which are serialized by the built in serialization yet can't be externally serialized

In short I understand the reason for the change, but to have the rug pulled out from under what was previously reliable working code, with no real workable solution has left me quite disappointed with Xamarin's approach.

Comment 3 Sebastien Pouliot 2015-05-25 09:32:37 UTC
Hello Brad,

1/2. You can try to access the data and determine if it makes sense. That should trigger an exception or give you something empty. Not ideal but it's something you can trigger on...

3. It could happen on other types, but it's unlikely to happen again on CookieContainer. Matching MS implementation is a one way trip (and MS, like mono, does it best not to change format needlessly);

4/5. You might want to try reflection (to serialize the data). Also you could manually deserializing the data, but it's a more complex approach

Switching to MS reference sources has a lot of advantages but sadly, like you found out, there are some inconveniences too :(