通过更改默认 CLR 探测顺序从自定义位置加载程序集 方法一:将目录添加到私有探测路径方法 2:通过连接程序集解析事件方法三:在配置中使用codebase标签

问题描述

我有一个应用程序,它在与应用程序相同的目录中包含其所有依赖项,因此一切正常。但是,我希望能够按需从自定义位置加载程序集。该位置在应用程序启动之前是已知的,但重要的一点是应该从自定义位置加载程序集即使它们存在于应用程序基目录中

以下是我尝试过的一些方法

方法一:将目录添加到私有探测路径

// This method does not work for assemblies outside the app directory. Also,it ignores the private path if the assembly is present in the app directory
        private static void ConfigureCustomAssemblyLoading1(string directory)
        {
            AppDomain.CurrentDomain.AppendPrivatePath(directory);
        }

方法 2:通过连接程序集解析事件

// The AssemblyResolve event is only fired if the resolution fails,so the assembly will not be loaded from custom path if present in app directory
        private static void ConfigureCustomAssemblyLoading2(string directory)
        {
            AppDomain.CurrentDomain.AssemblyResolve += (sender,args) =>
            {
                var requestedAsm = args.Name.Split(',')[0];
                var files = Directory.GetFiles(directory);
                foreach (var file in files)
                {
                    var asm = Path.GetFileNameWithoutExtension(file);
                    if (asm.Equals(requestedAsm))
                        return Assembly.LoadFrom(file);
                }

                return null;
            };
        }

方法三:在配置中使用codebase标签

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Calculator"/>
        <codeBase version="1.0.0.0"
                  href="file://C:\test\Calculator.dll"/>
      </dependentAssembly>
    </assemblyBinding>

这优先于本地应用程序基目录,但是,由于有数百个依赖程序集,这不是一个方便的解决方案。如果我能指定探测目录,就可以解决问题。

下面是一个示例程序来尝试这个:

        private static void Main(string[] args)
        {
            const string customDirectory = @"C:\test"; // force load assembly from here
            //ConfigureCustomAssemblyLoading1(customDirectory);
            ConfigureCustomAssemblyLoading2(customDirectory);
            CalculateSum();
            Console.ReadLine();
        }

        private static void CalculateSum()
        {
            var sum = CustomMath.Sum(1,1);
            Console.WriteLine($"In case you do not kNow,sum of 1 and 1 is {sum}");
        }

解决方法

正如上面评论中所指出的,您不应该替换在构建过程中静态链接的库。如果程序集不是强命名的(未签名),这 可能 可以工作,但不能保证在 .NET 世界中工作和不好的做法。代码签名不仅是确保代码不被操纵的一种方式,而且还确保构建是一致的,并且您不会意外地混合来自不同构建的库。如果库与预期版本不匹配,则构建中的问题可能会导致未定义的行为。

如果需要动态加载库(这本身是完全有效的),请在共享程序集中使用具有公共接口层的反射。