Locked assembly binding to redirect to a different assebly file

  • Thursday, May 10, 2012 9:43 AM
     
      Has Code

    Hello,

    i transfered a class to a different assembly but kept the same namespaces. My application is deserializing a file that contains type references to this class and now i get exceptions because it is looking for the old assebly. So i created a SerializationBinder decendant to handle that, but although the BindToType method is called for other types that have also been moved, it is never called for the class type that is causing the exception.

    The next thing i did was to add a CodeBase reference to the applications config file to point to new assebly that contais that type but still i get the same excpetion that the old assembly file cannot be located

    My original class was structured like this:

    Assembly file MyLib.Classes.dll (version 1.0.0.0)

         Namespace MyLib.Classes

             Public Class TestClass


    and then like this:

    Assembly file MyLib.dll (version 1.0.0.1)

         Namespace MyLib.Classes

             Public Class TestClass


    my serializationbinder looks like this:

    Public Class CustomSerializationBinder
        Inherits Runtime.Serialization.SerializationBinder
    
        Public Overrides Function BindToType(assemblyName As String, typeName As String) As System.Type
    
            assemblyName = assemblyName.Replace("MyLib.Classes, Version=1.0.0.0", "MyLib Version=1.0.0.1")
            typeName = assemblyName.Replace("MyLib.Classes, Version=1.0.0.0", "MyLib Version=1.0.0.1")
            Return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName))
    
        End Function
    
    End Class

    the deserialization code is like this:

    Dim Bytes() As Byte = value
    Using Stream As New IO.MemoryStream(Bytes) With {.Position = 0}
        Dim b As New Runtime.Serialization.Formatters.Binary.BinaryFormatter() With {.Binder = New CustomSerializationBinder()}
        Return b.Deserialize(Stream)
    End Using

    and finally my configuration file looks like this:

    <runtime>
       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  
          <dependentAssembly>
             <assemblyIdentity name="MyLib.Classes" publicKeyToken="e9a4f5adb9bd741c" culture="neutral" />
             <CodeBase Version="1.0.0.1" href="file:///c:\temp\MyLib.dll" />
          </dependentAssembly>
       </assemblyBinding>
    </runtime>

    MyLib.Classes.dll and MyLib.dll are strong name assemblies.


    Upon deserialization i get the following exception:

    Message: Could not load file or assembly 'MyLib.Classes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e9a4f5adb9bd741c' or one of its dependencies. The system cannot find the file specified.

    Stack Trace:   at System.Reflection.Assembly._GetType(String name, Boolean throwOnError, Boolean ignoreCase)
       at System.UnitySerializationHolder.GetRealObject(StreamingContext context)
       at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder)
       at System.Runtime.Serialization.ObjectManager.DoFixups()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at .......

    Fusion.Log:=== Pre-bind state information ===
    LOG: User = PC2\Theodore
    LOG: DisplayName = MyLib.Classes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e9a4f5adb9bd741c
     (Fully-specified)
    LOG: Appbase = file:///D:/.../MyApp/bin/x86/Debug/
    LOG: Initial PrivatePath = NULL
    Calling assembly : (Unknown)
    ===
    LOG: This bind starts in default load context.
    LOG: Using application configuration file: D:\...\MyApp\bin\x86\Debug\MyApp.vshost.exe.Config
    LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
    LOG: Post-policy reference: MyLib.Classes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e9a4f5adb9bd741c
    LOG: Attempting download of new URL file:///D:/.../MyApp/bin/x86/Debug/MyLib.Classes.DLL.
    LOG: Attempting download of new URL file:///D:/.../MyApp/bin/x86/Debug/MyLib.Classes.DLL/MyLib.Classes.DLL.
    LOG: Attempting download of new URL file:///D:/.../MyApp/bin/x86/Debug/MyLib.Classes.EXE.
    LOG: Attempting download of new URL file:///D:/.../MyApp/bin/x86/Debug/MyLib.Classes.EXE/MyLib.Classes.EXE.

    Is there a way around this problem?

    Regards,

    Theodore


    Theo

All Replies

  • Thursday, May 10, 2012 3:45 PM
     
     Answered Has Code

    I solved this problem on own and i share it for the benefit of everyone who cares to know.

    I added a handler to the application domain's AssemblyResolve event and there i loaded the new assembly.

    AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolver
    
    Private Function AssemblyResolver(ByVal source As Object, ByVal e As ResolveEventArgs) As Reflection.Assembly
    
            If e.Name.Contains("MyLib.Classes") Then
                Return Reflection.Assembly.Load("MyLib, Version=1.0.0.1, Culture=neutral, PublicKeyToken=e9a4f5adb9bd741c")
    
            Else : Return Nothing 'Reflection.Assembly.Load(e.Name)
            End If
    
    End Function



    Theo

    • Marked As Answer by theodorep Thursday, May 10, 2012 3:45 PM
    •