Is it possible to replace a reference to a strongly-named assembly with a "weak" reference?

Viewed 5839

I'm writing a .NET tool that requires the SQL Server SMO library. I don't care if it's the version from Server 2005 (9.0), 2008 (10.0) or 2008 R2 (probably 10.5, didn't check). The SMO library is installed together SQL Server, so I can safely assume that on any system with SQL Server installed, some version of the SMO library is available as well.

Unfortunately, the SMO libraries are strongly-named: If I add a reference to SMO 9.0 in my project, it will fail (FileNotFoundException) if only SMO 10.0 is present on the customer's system, and vice versa.

Is there some way to tell the compiler that any version of the library is fine for me? Or do I really have to distribute 3 identical versions of my tool, each compiled to a different version of the SMO?


Disclaimer: I do know that the SMO libraries (and the libraries required by the SMO libraries) can be redistributed. But there's a big difference between (a) one slim 100KB standalone EXE and (b) a full-blown setup package that installs a whole bunch of prerequisites.

Disclaimer 2: I am aware of the following duplicates:

The solutions provided do not fit, however. In question 1, the developer has control over the referenced DLL (which I do not); in question 2, the developer has control over the target systems (which I do not either).

3 Answers

Based on Ladislav's suggestion of overriding AssemblyResolve, I was able to come up with the following solution:

Sub Main()
    ...
    Dim assembly = GetSmoAssembly()
    If assembly Is Nothing Then
        ' no suitable Version of SMO found
        ...
    Else
        ' load correct assembly
        Dim returnAssembly As ResolveEventHandler = Function() assembly
        AddHandler AppDomain.CurrentDomain.AssemblyResolve, returnAssembly
        TestSmo()
        RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, returnAssembly
    End If
    ...
End Sub

Private Function GetSmoAssembly() As Assembly
    Try
        Return Assembly.Load("Microsoft.SqlServer.Smo, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91")
    Catch ex As FileNotFoundException
    End Try

    Try
        Return Assembly.Load("Microsoft.SqlServer.Smo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91")
    Catch ex As FileNotFoundException
    End Try

    Return Nothing
End Function

' Needs to be in a separate method, see https://stackoverflow.com/q/6847765/87698
Private Sub TestSmo()
    Dim srv As New Smo.Server()
End Sub

Note: Using Assembly.Load directly in the AssemblyResolve event handler is not a good idea, since it recursively calls the event handler if Load fails.

Related