我有一个引用Microsoft.SqlServer.Smo程序集的.net应用程序。 程序集不随应用程序一起分发。而是sql sdk安装在系统中,并且dll在GAC中注册,以便应用程序可以加载。 这没有问题,除了在某些目标机器上我有SDK的v12,而在其他目标机器上我有SDK的v13(通常安装了SSMS)。 我希望应用程序加载系统上可用的任何内容的最新版本,因此v13或v12(如果不可用)。 是否可以在代码中或通过应用程序配置实现此目的?
答案 0 :(得分:0)
问题的简短回答是将 SpecificVersion 设置为false,正如@sevzas正确建议的那样。
无论如何,如果在系统上安装了SSMS 2016更新13.0.16000.28,那么dll的13.100.0.0将在GAC中注册,并且通过上述更改,这是它将被加载的版本。不幸的是,这个版本并不是由第三方开发人员使用,而是仅由Microsoft产品使用,因此尝试加载它将产生异常(see here)。有人可能想知道为什么他们在GAC中注册它,如果他们不想让人们使用它。
无论如何,我找到了一种方法,通过使用程序集解析事件,使用以下代码加载v13.0(或之前或未来14)。
static int Main(string[] args)
{
//we set an event handler at the begging of our program
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
//your stuff
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//if the dll is a sqlserver dll, we do our trick
if(args.Name.StartsWith("Microsoft.SqlServer"))
return LoadSqlAssembly(args.Name);
return null;
}
private static readonly int[] SqlVersions = new int[] {14, 13, 12, 11};
private static bool _reEntry = false;
private static Assembly LoadSqlAssembly(string name)
{
if (_reEntry)
return null;
name = name.Split(',')[0];
foreach (var version in SqlVersions)
{
try
{
_reEntry = true;
var ret = Assembly.Load($"{name}, Version={version}.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL");
//Logger.InfoFormat("Loaded {0} version {1}", name, version);
return ret;
}
catch (Exception)
{
//ignore exception
}
finally
{
_reEntry = false;
}
}
return null;
}
```