我正在开发一个应用程序,该应用程序引用并使用某些供应商提供的一些第三方程序集。在开发箱中,我的源代码树的引用文件夹中有这三个程序集,可以引用它们并构建应用程序,该应用程序可以构建但由于未安装整个服务器应用程序而无法运行,但这很好。
在我要复制此自定义应用程序并运行我引用的所有程序集的服务器上,它们位于以下文件夹中:
D:\ProgramFiles\VendorName\ProductName\Support\API\Bin64
如果将我的小型可执行文件复制到该文件夹中并运行它,则可以正常运行,但是如果我将.exe放在一个更合适的文件夹中,例如:
D:\ProgramFiles\MyCompanyName\MyProduct\bin\...
它无法工作,因为它无法解析这些程序集。
我知道我可以在app.config中使用探测来指定我的exe必须在哪些文件夹中查找引用,但万一情况下,程序集不在子文件夹中,而在完全不同的位置。
我不想将所有供应商程序集都复制到我的app文件夹中,我不能只在其中放置我要引用的3个程序集,因为它们也正在加载其他程序集,除非我拥有所有这些程序集(很多…),否则它不会工作。
我没有做任何特别的事情,没有创建应用程序域,也没有通过反射加载程序集,只是希望CLR在应用程序启动或执行时需要解析引用。
谢谢。
编辑:这是最终的工作代码
static System.Reflection.Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { Logger logger = new Logger(); try { string RMSAssemblyFolder = ConfigurationManager.AppSettings["RMSAssemblyFolder"]; Assembly MyAssembly = null; string strTempAssmbPath = string.Empty; Assembly objExecutingAssemblies = Assembly.GetExecutingAssembly(); AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies(); AssemblyName myAssemblyName = Array.Find<AssemblyName>(arrReferencedAssmbNames, a => a.Name == args.Name); if (myAssemblyName != null) { MyAssembly = Assembly.LoadFrom(myAssemblyName.CodeBase); } else { strTempAssmbPath = Path.Combine(RMSAssemblyFolder, args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll"); if (!string.IsNullOrEmpty(strTempAssmbPath)) { if (File.Exists(strTempAssmbPath)) { logger.Information("Assembly to load: {0} - File was found in: {1}", args.Name, strTempAssmbPath); // Loads the assembly from the specified path. MyAssembly = Assembly.LoadFrom(strTempAssmbPath); } } } // Returns the loaded assembly. return MyAssembly; } catch (Exception exc) { logger.Error(exc); return null; } }
您应该首先找到这些dll的安装文件夹,然后用于AppDomain.AssemblyResolve挂钩程序集解析并尝试从此文件夹加载请求的程序集。
AppDomain.AssemblyResolve
它看起来像这样(未经测试,您需要检查到底args.Name包含什么,可能包含版本和强名称以及类型名称):
args.Name
var otherCompanyDlls = new DirectoryInfo(companyFolder).GetFiles("*.dll"); AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var dll = otherCompanyDlls.FirstOrDefault(fi => fi.Name == args.Name); if (dll == null) { return null; } return Assembly.Load(dll.FullName); };