Crainiate Community

Support and discussion for users of Crainiate component software products
Welcome to Crainiate Community Sign in | Join | Help
in Search

Custom serialization binder

Last post 01-29-2008 3:42 PM by laurian. 6 replies.
Page 1 of 1 (7 items)
Sort Posts: Previous Next
  • 01-23-2008 3:44 PM

    Custom serialization binder

     Hi,

    I would like to make it possible to load diagrams from previous versions of my assembly. If I don't do anything, I get "BindingFailure was detected" when I call Diagram.Open. I've searched for solutions in the web and what I've found use the formatter (System.Runtime.Serialization.IFormatter). As the exception is produced after calling Diagram.OnDeserialize, I suppose I have to do my changes to the formatter in this method. Here is my method:

    protected override void OnDeserialize(System.Runtime.Serialization.IFormatter formatter, System.Runtime.Serialization.SurrogateSelector selector)
            {
                ((System.Runtime.Serialization.Formatters.Soap.SoapFormatter)formatter).AssemblyFormat =
                    System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
                List<Version> authorised_versions = new List<Version>();
                authorised_versions.Add(new Version(2, 2, 1, 0));
                authorised_versions.Add(new Version(2, 2, 2, 0));
                formatter.Binder = new MultipleAssemblySerializationBinder(authorised_versions);

                MySerialize surrogate = new MySerialize();
                selector.AddSurrogate(typeof(MyDiagram), new StreamingContext(StreamingContextStates.All), surrogate);

                base.OnDeserialize(formatter, selector);
            }

    Here my changes to the formatter are:

    • formatter.AssemblyFormat -> Simple
    • formatter.Binder -> my custom binder:
    sealed class MultipleAssemblySerializationBinder : SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            assemblyName = assembly.FullName;
            return assembly.GetType(typeName);
        }
    }

     This should allow types from any assembly.

    My problem is that I still get the exception and "BindToType" is never called... What am I doing wrong?

     

    PS: in the file saved, here is the line that causes me the problems (if I change 2.2.1.0 to 2.2.2.0 then I don't have to do anything):

     <assembly id="ref-159">MyAssembly, Version=2.2.1.0, Culture=neutral, PublicKeyToken=blahblahblah</assembly>

    • 213.139.4.250
  • 01-24-2008 9:44 AM In reply to

    Re: Custom serialization binder

    The problem may be that we use our own binder, DiagramBinder. You should inherit from DiagramBinder, and call the base method for types you do not wish to handle.

    To set the binder instance as an instance of your class during serialization, use the Component.Instance.DefaultBinder property.

    Filed under:
    • 86.137.241.65
  • 01-24-2008 3:18 PM In reply to

    Re: Custom serialization binder

     Thanks, This way my binder is called... But it seems I can't solve the problem that way: BindToType is never called with a wrong assemblyName (in fact each time it is called for an assemby of mine it just gives me the name of the assembly, not the full name (with the version, the culture and the key)).

    Anyway, I searched more and I've found that: http://dsrg.mff.cuni.cz/projects/mono/diffs/showdiff.php?old=2004-11-05&new=2004-11-30&fileIndex=220&bench=
    In System.DelegateSerializationHolder.DeserializeDelegate, they load an assembly by its full name and I think the problem is here: The deserialization asks for the delegate type (calling my BindToType), and then tries to deserialize it. The XML holds information on an assembly, and DeserializeDelegate tries to load this assembly which lead to my problem as this assembly no longer exist.

    So the solution would be to change the assembly entry on the SerializationInfo given to DeserializeDelegate. How can I do that?!

    I hope I've explained it well... If that helps, I thinks these guys had the same problem: http://www.x-tensive.com/Forum/viewtopic.php?t=777

    I also put more information on

    • the exception:
      • in Crainiate.ERM4.Diagram.x16cebda0b690ada5(Stream x84378c276c4cd7e2, IFormatter xb18a47820b01ac5a)
        in Crainiate.ERM4.Diagram.Open(String path, LoadFormat format)
    • the serialized delegate:

     <a5:MyClass id="ref-37" xmlns:a5="http://schemas.microsoft.com/clr/nsassem/MyNamespace/MyProduct">
    <MyEventHandler href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-89"/>
    ...
    </a5:MyClass>

    <a3:DelegateSerializationHolder id="ref-89" xmlns:a3="http://schemas.microsoft.com/clr/ns/System">
    <Delegate href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-142"/>
    <target0 href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-29"/>
    <method0 href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-143"/>
    </a3:DelegateSerializationHolder>

    <a3:DelegateSerializationHolder_x002B_DelegateEntry id="ref-142" xmlns:a3="http://schemas.microsoft.com/clr/ns/System">
    <type id="ref-158">MyNamespace.MyOtherClass+MyOtherClassHandler</type>
    <assembly id="ref-159">MyProduct, Version=2.2.1.0, Culture=neutral, PublicKeyToken=blahblahblah</assembly>
    <target id="ref-160" xsi:type="SOAP-ENC:string">target0</target>
    <targetTypeAssembly href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-159"/>
    <targetTypeName id="ref-161">MyNamespace.MyOtherOtherClass</targetTypeName>
    <methodName id="ref-162">MyMethod</methodName>
    <delegateEntry xsi:null="1"/>

    </a3:DelegateSerializationHolder_x002B_DelegateEntry>
    <a9:MemberInfoSerializationHolder id="ref-143" xmlns:a9="http://schemas.microsoft.com/clr/ns/System.Reflection">
    <Name href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-162"/>
    <AssemblyName href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-159"/>
    <ClassName href="http://support.crainiate.net/Community/forums/AddPost.aspx?ReplyToPostID=659&Quote=False#ref-161"/>
    <Signature id="ref-163">Void MyMethod(System.Object)</Signature>
    <MemberType>8</MemberType>
    <GenericArguments xsi:null="1"/>
    </a9:MemberInfoSerializationHolder>

     Here I would like to change the string of ref-159 to MyProduct, Version=2.2.2.0, Culture=neutral, PublicKeyToken=blahblahblah


     

    • 213.139.4.250
  • 01-27-2008 11:25 PM In reply to

    Re: Custom serialization binder

    That link may be misleading - it appears to be about deserializing delegates.

     I'd like to try and get back to basics here so hopefully we can help in some way.

     To summarize: you have created diagrams with custom classes which have then been serialized into a file. When you upgraded your assembly, you found existing files no longer loaded?

    Many thanks
    James

     

    • 86.130.74.93
  • 01-28-2008 8:51 AM In reply to

    Re: Custom serialization binder

     Yes that's it. I have custom shapes that inherit Crainiate.ERM4.Shape and holds an event handler (with is therefore a delegate). The problem occurs deserializing files from older versions of my assembly.

    • 213.139.4.250
  • 01-28-2008 6:54 PM In reply to

    Re: Custom serialization binder

    Ok. Do you override the GetObjectData methods to add your custom properties to the serializationinfo object and deserialize the custom objet through the protected constuctor ?

     

    • 81.129.13.133
  • 01-29-2008 3:42 PM In reply to

    Re: Custom serialization binder

    I do.

    But my problem is only for backward compatibility: now I don't serialize the delegates anymore... 

    • 213.139.4.250
Page 1 of 1 (7 items)