Search Unity

Unity BinaryFormatter Deserialization Problem

Discussion in 'Editor & General Support' started by tgraupmann, Dec 30, 2008.

  1. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    Unity is having an issue selecting the right object for deserialization.

    I have successfully serialized to a file and then deserialized from that file in binary format.

    But when I try to deserialize from a URL, I'm getting a deserialization error.

    The attached project includes a Unity project and a Mono project.

    Both versions attempt to deserialize a Mono binary serialized file and a Unity serialized file.

    With the same code, MonoDevelop is able to execute the Mono project and get the expected result.

    Unfortunately, the Unity editor is getting a deserialization error.

    You will find the MonoProject solution in Deserialization002/MonoProject

    The expected output running from Mono should be:
    Code (csharp):
    1. From File: Deserialized okay
    2. From Unity Url: Failed to deserialize
    3. From Mono Url: Deserialized okay
    The expected output running from the Unity editor should be:
    Code (csharp):
    1. From File: Deserialized okay
    2. From Unity Url: Deserialized okay
    3. From Mono Url: Failed to deserialize
    The expected output running from the Unity player should be:
    Code (csharp):
    1. From File: Failed to deserialize
    2. From Unity Url: Deserialized okay
    3. From Mono Url: Failed to deserialize
    This is the Unity serialized url:
    http://tagenigma.com/qa/Unity3d/WIP/Maps/TF_CityMap_Unity.txt

    This is the Mono serialized url:
    http://tagenigma.com/qa/Unity3d/WIP/Maps/TF_CityMap_Mono.txt

    Here are the rrror details:

    Code (csharp):
    1. System.IO.FileNotFoundException: Could not load file or assembly '8b8fe8916a42f423e841d8c0e08ffe85' or one of its dependencies. The system cannot find the file specified.
    2. File name: '8b8fe8916a42f423e841d8c0e08ffe85'
    3.   at <0x00000> <unknown method>
    4.   at (wrapper managed-to-native) System.AppDomain:LoadAssembly (string,System.Security.Policy.Evidence,bool)
    5.   at System.AppDomain.Load (System.String assemblyString) [0x00000]
    6.   at (wrapper remoting-invoke-with-check) System.AppDomain:Load (string)
    7.   at System.Reflection.Assembly.Load (System.String assemblyString) [0x00000]
    8.   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className) [0x00000]
    9.   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadType (System.IO.BinaryReader reader, TypeTag code) [0x00000]
    10.   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadTypeMetadata (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo) [0x00000]
    11.   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectInstance (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo, System.Int64 objectId, System.Object value, System.Runtime.Serialization.SerializationInfo info) [0x00000]
    12.   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) [0x00000]
    13.   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) [0x00000]
    14.   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (System.IO.BinaryReader reader) [0x00000]
    15.   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (System.IO.BinaryReader reader, Boolean readHeaders, System.Object result, System.Runtime.Remoting.Messaging.Header[] headers) [0x00000]
    16.   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) [0x00000]
    17.   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) [0x00000]
    18.   at SerializeCache.DeserializeUrl (System.String url, System.Type type) [0x0002a] in /Users/user/Unity/Deserialization002/Assets/SerializeCache.cs:138
    19. UnityEngine.Debug:LogError(Object)
    20.  
     

    Attached Files:

  2. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    I tried using the WWW.bytes to deserialize but I get the same error.

    I'm doing the following:
    Code (csharp):
    1.     // Use this for initialization
    2.     IEnumerator Start ()
    3.     {
    4.         UnityEngine.WWW www =
    5.             new WWW(_TerrainFragmentMapUnityUrl);
    6.         yield return www;
    7.        
    8.         BinaryFormatter bf =
    9.             new BinaryFormatter();
    10.        
    11.         using (MemoryStream ms =
    12.                new MemoryStream([url]www.bytes[/url], 0, [url]www.bytes.Length[/url]))
    13.         {
    14.             _TerrainFragmentList =
    15.                 (List<TerrainFragment>)bf.Deserialize(ms);
    16.         }
    17.        
    18.         _GuiText.text = AttemptSerialization();    
    19.         UnityEngine.Debug.Log(_GuiText.text);
    20.     }
    And the editor gives me the following error.
    Code (csharp):
    1. FileNotFoundException: Could not load file or assembly '8b8fe8916a42f423e841d8c0e08ffe85' or one of its dependencies. The system cannot find the file specified.
    2. System.AppDomain.Load (System.String assemblyString)
    3. (wrapper remoting-invoke-with-check) System.AppDomain:Load (string)
    4. System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream)
    5. TAGTerrainScript+<>c__CompilerGenerated0.MoveNext ()   (at Assets/TAGTerrainScript.cs:35)
     

    Attached Files:

  3. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    This is basically how I do it (exact code untested):

    Code (csharp):
    1. private WWW webStream;
    2. private bool downloading;
    3.  
    4. public void Start
    5. {
    6.     webStream = new WWW( "http://my.file.name" );
    7.     downloading = true;
    8. }
    9.  
    10. public void Update()
    11. {
    12.     if( downloading  webStream.isDone )
    13.     {
    14.         downloading = false;
    15.         HandleData( webStream.bytes );
    16.     }
    17. }
    18.  
    19. public void HandleData( byte[] data )
    20. {
    21.     MySpecialClass myObject;
    22.     MemoryStream memoryStream;
    23.     BinaryFormatter binaryFormatter;
    24.    
    25.     memoryStream = new MemoryStream( data );
    26.     binaryFormatter = new BinaryFormatter();
    27.    
    28.     myObject = binaryFormatter.Deserialize( memoryStream ) as MySpecialClass;
    29.    
    30.     // Handle //
    31. }
     
  4. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    Ok to wrap this up from the IRC discussion. The error comes from unity producing a differently named assembly on each build which causes problems with serialisation of contained classes.

    A workaround is to define all data classes for serialisation in external assemblies.

    This should be bug reported though.
     
  5. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    The core issue here is that the Unity compiled assembly name changes (looks like a guid). And therefore, the assembly cannot be found for deserialization.

    The painful workaround is to put the data structures into external DLL assets.
     
  6. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    I moved the deserialization structures to an external assembly and added the asset. Unfortunately, I get the same error.

    I'll make another attempt to serialize with the external class to see if that works.
     

    Attached Files:

  7. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    The binary signature has to match for an object to be capable of being deserialized.

    Now since both the Mono project and the Unity project use the external assembly to store the data structures, the serialized objects can be exchanged.

    This example works in both the Unity Editor and the Unity Player.

    The serialized object can be generated in Unity or the Mono project and the player will be capable of deserializing it.
     

    Attached Files:

  8. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    The WWW class appears to be required. With HttpWebRequest deserialization is working on MonoDevelop and Unity Editor, but not the Unity Player.

    Looks like I'm fighting security here.
    Code (csharp):
    1. (Filename: /Users/unity-build/Desktop/automatic-build-2/unity/Projects/../Runtime/Export/Generated/BaseClass.cpp Line: 1651)
    2.  
    3. System.NotSupportedException: [url]http://tagenigma.com/qa/unity3d/wip/maps/tf_citymap_external.txt[/url]
    4.   at System.Net.WebRequest.GetCreator (System.String prefix) [0x00000]
    5.   at System.Net.WebRequest.Create (System.Uri requestUri) [0x00000]
    6.   at System.Net.WebRequest.Create (System.String requestUriString) [0x00000]
    7.   at SerializeCache.DeserializeUrl (System.String url, System.Type type) [0x00000]
    8. UnityEngine.Debug:LogError(Object)
    9. SerializeCache:DeserializeUrl(String, Type)
    10. TAGTerrainScript:AttemptSerialization()
    11. TAGTerrainScript:Start()
    12.  
    13. (Filename: /Users/unity-build/Desktop/automatic-build-2/unity/Projects/../Runtime/Export/Generated/BaseClass.cpp Line: 1651)
    14.  
    15. From Binary Url: Failed to deserialize
    16.  
    17. UnityEngine.Debug:Log(Object)
    18. TAGTerrainScript:Start()
    19.  
    20. (Filename: /Users/unity-build/Desktop/automatic-build-2/unity/Projects/../Runtime/Export/Generated/BaseClass.cpp Line: 1651)
    21.  
     

    Attached Files:

  9. dkoontz

    dkoontz

    Joined:
    Aug 7, 2009
    Posts:
    198
    Was this ever reported as a bug? I'm running into this same issue in Unity 3 so it's clearly not been fixed.
     
  10. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
  11. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Necro or not, this is still an issue.

    I appreciate the link to the SerializationBinder docs, but I don't find them terribly enlightening... does anyone have a simple example of how you would use this to make serialization work in the web player?