.net加载最新版本的程序集

时间:2017-03-21 14:37:26

标签: c# .net sql-server app-config smo

我有一个引用Microsoft.SqlServer.Smo程序集的.n​​et应用程序。 程序集不随应用程序一起分发。而是sql sdk安装在系统中,并且dll在GAC中注册,以便应用程序可以加载。 这没有问题,除了在某些目标机器上我有SDK的v12,而在其他目标机器上我有SDK的v13(通常安装了SSMS)。 我希望应用程序加载系统上可用的任何内容的最新版本,因此v13或v12(如果不可用)。 是否可以在代码中或通过应用程序配置实现此目的?

1 个答案:

答案 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;
    }

```