Assembly independent binary de-/serialization (II)


#1

I’ve found this closed thread from @haavard:

I have exactly the same problem: I want to serialize/deserialize a class, all works fine except for that the dll must be in the 3dsMax root folder. I’ve tried others as bin, plugins, stdplugs… and nothing work.
Any idea how to make it work?

Here are the sample codes:
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Max;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace P3D
{

    [Serializable]
    public class Test_Serialize : ISerializable
    {
        private IINode node;
        private List<int> vertsID;

        public int[] VertsID
        {
            get
            {
                return vertsID.ToArray();
            }
        }
        public string nodeName
        {
            get
            {
                return node.Name;
            }
        }


        //////////////////////////////////////
        // CONSTRUCTORS
        //////////////////////////////////////


        public Test_Serialize(uint nodeHandle)
        {
            IGlobal global = GlobalInterface.Instance;
            IInterface14 ip = global.COREInterface14;
            node = ip.GetINodeByHandle(nodeHandle);

            vertsID = Enumerable.Range(0, node.NumSubs).ToList();
        }

        public Test_Serialize(SerializationInfo info, StreamingContext context)
        {
            vertsID = (List<int>)info.GetValue("vertsID", typeof(List<int>));
            string nodeName = info.GetString("nodeName");
            IGlobal global = GlobalInterface.Instance;
            IInterface14 ip = global.COREInterface14;
            node = ip.GetINodeByName(nodeName);
        }


        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("vertsID", vertsID);
            info.AddValue("nodeName", node.Name);
        }

        //////////////////////////////////////
        // SERIALIZATION METHODS
        //////////////////////////////////////
        public void SerializeTestObject(string filename)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(filename,
                                     FileMode.Create,
                                     FileAccess.Write, FileShare.None);
            formatter.Serialize(stream, this);
            stream.Close();
        }

        public Test_Serialize Deserialize(string filename)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(filename,
                                      FileMode.Open,
                                      FileAccess.Read,
                                      FileShare.Read);
            Test_Serialize test = (Test_Serialize)formatter.Deserialize(stream);
            stream.Close();
            return test;
        }
    }
}

And in MaxScript:

		dotNet.loadAssembly @"C:\Program Files\Autodesk\3ds Max 2016\Test_Serialize.dll"
	
		the_Object = $
		handleObj = the_Object.inode.handle

		TestObj = dotnetObject "P3D.Test_Serialize" handleObj 		-- OK, creates object
		TestObj.VertsID		-- OK, shows List<int>
		TestObj.nodeName		-- OK, gets the node's name
		
		TestObj.SerializeTestObject @"D:\_000-ANDRES\TEST\TestObj.bin"		-- OK, saves serialized object
		
		TestObj2 = TestObj.Deserialize @"D:\_000-ANDRES\TEST\TestObj.bin"		-- OK, only if dll is in the root folder
		TestObj2.VertsID		-- OK, good deserialization
		TestObj2.nodeName		-- OK, good deserialization
		

#2

read this thread please: https://social.msdn.microsoft.com/Forums/vstudio/en-US/e5f0c371-b900-41d8-9a5b-1052739f2521/deserialize-unable-to-find-an-assembly-?forum=netfxbcl

I think SerializationBinder is the right direction. Unfortunately, I don’t have time to play with it.
If you make it work, please submit a solution.

As soon as I find the time, I will also try to solve it myself.


#3

in a nutshell, it is necessary to force deserialization with the assembly that is already loaded in memory, and not to load it again using the path specified in the stream


#4

Yes, SerializationBinder is the solution.
I’ll post it tomorrow if someone is interested.
And I’ve found the way too to serialize/deserialize to/from appDataChunk.


#5

sounds very interesting


#6

It is for me. It’s the only way that has occurred to me to save DotNet object with the scene. The code has no difficulty: just save the serialized stream to the dataChunk instead of to a file.

For the SerializationBinder, I’ve just done a copy of the code from your link and added the binder to the formatter. Works fine at least for ‘first generation’ dll. I have to test it further, when the dll serializes an object with fields that reference objects defined in another dll (it’s my case, my object references a class called ‘Vector3D’ that I create one year ago in another project). I’ll tell you my progress.


#7

what version of SerializationBinder shown from that link do you use?

also it might be interesting to use on-the-fly (via mxs) assemblies as well


#8

I’m right now writing to you an email. :slight_smile:
I have problems with ‘second generation’ objects, so I prefer not to write yet the code.


#9

I can’t find a way to make it work. I give up.

Edit: yes it works! It was a problem of a duplicated name of a dll.