Я пишу .NET-инструмент, который требует библиотеки SMO SQL Server. Меня не волнует, была ли версия с сервера 2005 (9.0), 2008 (10.0) или 2008 R2 (вероятно, 10.5, не проверялась). Библиотека SMO установлена вместе с SQL Server, поэтому я могу с уверенностью предположить, что в любой системе с установленным SQL Server доступна некоторая версия библиотеки SMO.
К сожалению, библиотеки SMO сильно названы: если я добавлю ссылку на SMO 9.0 в свой проект, он потерпит неудачу (FileNotFoundException
), если в системе клиента присутствует только SMO 10.0 и наоборот.
Есть ли способ сообщить компилятору, что любая версия библиотеки подходит мне? Или мне действительно нужно распространять 3 идентичные версии моего инструмента, каждый из которых скомпилирован в другую версию SMO?
Отказ от ответственности: я знаю, что библиотеки SMO (и библиотеки, необходимые библиотекам SMO) могут быть перераспределены. Но есть большая разница между (a) одним тонким 100KB автономным EXE и (b) полномасштабным установочным пакетом, который устанавливает целую кучу предварительных условий.
Отказ от ответственности 2: Я знаю следующие дубликаты:
- С# - вы можете сделать "слабую" ссылку на сборку с сильной именованной сборкой
- Требуется сборка С# для ссылки на сильно именованную сборку
Однако предоставленные решения не подходят. В вопросе 1 разработчик имеет контроль над DLL, на которую ссылается (что у меня нет); в вопросе 2 разработчик имеет контроль над целевыми системами (чего я тоже не делаю).
Решение. Основываясь на предположении Ladislav о переопределении AssemblyResolve
, я смог придумать следующее решение:
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
Примечание. Использование Assembly.Load непосредственно в обработчике событий AssemblyResolve не является хорошей идеей, поскольку он рекурсивно вызывает обработчик события, если Load failed.