我的DLL由第三方應用程序加載,我們無法自定義。我的程序集必須位於它們自己的文件夾中。我無法將它們放入GAC(我的應用程序需要使用XCOPY進行部署)。 當根DLL嘗試從另一個DLL(在同一文件夾中)加載資源或類型時,加載失敗(FileNotFound)。 是否可以通過編程方式(從根DLL)將我的DLL所在的文件夾添加到程序集搜索路徑中?我不允許更改應用程序的配置文件。如何在運行時在.NET中將文件夾添加到程序集搜索路徑中?
回答
您可以將probing path添加到您的應用程序的.config文件,但只有探測路徑包含在您的應用程序的基本目錄中時才能使用。
聽起來像你可以使用AppDomain.AssemblyResolve事件,並手動加載DLL目錄中的依賴關係。
編輯(從評論):
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
{
string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
if (!File.Exists(assemblyPath)) return null;
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
謝謝,Mattias! 這工作: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve + = new ResolveEventHandler(LoadFromSameFolderResolveEventHandler); static Assembly LoadFromSameFolderResolveEventHandler(object sender,ResolveEventArgs args) string folderPath = Path。GetDirectoryName(Assembly.GetExecutingAssembly()的位置。); string assemblyPath = Path.Combine(folderPath,args.Name +「.dll」);裝配組件= Assembly.LoadFrom(assemblyPath); return assembly; } – isobretatel 2009-09-03 16:03:52
偉大的解決方案!這裏有一篇文章描述了其他一些解決方案,包括這一個詳細信息:http://kbalertz.com/897297/consume-assemblies-located-folder-different-application-folder-Visual-Basic.aspx(警告:它的VB ,而不是C#,有點舊) – Domenic 2011-12-21 20:51:41
如果你想「後備」到基本的解析器,你會怎麼做。例如'if(!File.Exists(asmPath))return searchInGAC(...);' – 2017-01-29 22:25:02
直視AppDomain.AppendPrivatePath(不建議使用)或AppDomainSetup.PrivateBinPath
From [MSDN](http://msdn.microsoft.com/en-us/library/system.appdomainsetup.aspx):Changing AppDomainSetup實例的屬性不會影響任何現有的AppDomain。當使用AppDomainSetup實例作爲參數調用CreateDomain方法時,它只會影響創建新的AppDomain。 – Nathan 2011-08-10 16:11:45
['AppDomain.AppendPrivatePath'](https://msdn.microsoft.com/en-us/library/system.appdomain.appendprivatepath%28v=vs.110%29.aspx)的文檔似乎表明它應該支持動態擴展AppDomain的搜索路徑,只是該功能已被棄用。如果它工作,這是一個比重載'AssemblyResolve'更清潔的解決方案。 – binki 2015-04-08 06:01:20
最好的解釋from MS itself:
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
//Retrieve the list of referenced assemblies in an array of AssemblyName.
Assembly MyAssembly, objExecutingAssembly;
string strTempAssmbPath = "";
objExecutingAssembly = Assembly.GetExecutingAssembly();
AssemblyName[] arrReferencedAssmbNames = objExecutingAssembly.GetReferencedAssemblies();
//Loop through the array of referenced assembly names.
foreach(AssemblyName strAssmbName in arrReferencedAssmbNames)
{
//Check for the assembly names that have raised the "AssemblyResolve" event.
if(strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
{
//Build the path of the assembly from where it has to be loaded.
strTempAssmbPath = "C:\\Myassemblies\\" + args.Name.Substring(0,args.Name.IndexOf(","))+".dll";
break;
}
}
//Load the assembly from the specified path.
MyAssembly = Assembly.LoadFrom(strTempAssmbPath);
//Return the loaded assembly.
return MyAssembly;
}
'AssemblyResolve'用於CurrentDomain,不適用於另一個域'AppDomain.CreateDomain' – Kiquenet 2015-12-01 13:24:51
更新框架4
由於Framework 4提升了Assembl yResolve事件也適用於資源,實際上這個處理程序更好。它基於本地化在app子目錄中的概念(其中一個用於本地化與文化的名稱,即C:\ MyApp \ it意大利語) 裏面有資源文件。 如果本地化是國家地區,即it-IT或pt-BR,則處理程序也起作用。在這種情況下,處理程序「可能會多次調用:對於後備鏈中的每種文化都會調用一次」[來自MSDN]。這意味着如果我們爲「it-IT」資源文件返回null,框架會引發事件詢問「it」。
事件掛鉤
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);
事件處理
Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string applicationDirectory = Path.GetDirectoryName(executingAssembly.Location);
string[] fields = args.Name.Split(',');
string assemblyName = fields[0];
string assemblyCulture;
if (fields.Length < 2)
assemblyCulture = null;
else
assemblyCulture = fields[2].Substring(fields[2].IndexOf('=') + 1);
string assemblyFileName = assemblyName + ".dll";
string assemblyPath;
if (assemblyName.EndsWith(".resources"))
{
// Specific resources are located in app subdirectories
string resourceDirectory = Path.Combine(applicationDirectory, assemblyCulture);
assemblyPath = Path.Combine(resourceDirectory, assemblyFileName);
}
else
{
assemblyPath = Path.Combine(applicationDirectory, assemblyFileName);
}
if (File.Exists(assemblyPath))
{
//Load the assembly from the specified path.
Assembly loadingAssembly = Assembly.LoadFrom(assemblyPath);
//Return the loaded assembly.
return loadingAssembly;
}
else
{
return null;
}
}
對於C++/CLI的用戶,這裏是@Mattias S」的答案(這爲我的作品):
using namespace System;
using namespace System::IO;
using namespace System::Reflection;
static Assembly ^LoadFromSameFolder(Object ^sender, ResolveEventArgs ^args)
{
String ^folderPath = Path::GetDirectoryName(Assembly::GetExecutingAssembly()->Location);
String ^assemblyPath = Path::Combine(folderPath, (gcnew AssemblyName(args->Name))->Name + ".dll");
if (File::Exists(assemblyPath) == false) return nullptr;
Assembly ^assembly = Assembly::LoadFrom(assemblyPath);
return assembly;
}
// put this somewhere you know it will run (early, when the DLL gets loaded)
System::AppDomain ^currentDomain = AppDomain::CurrentDomain;
currentDomain->AssemblyResolve += gcnew ResolveEventHandler(LoadFromSameFolder);
我'使用了@Mattias S'解決方案。如果您確實想要解析來自同一文件夾的依賴關係 - 則應嘗試使用請求程序集的位置,如下所示。 args.RequestingAssembly應該檢查無效。
System.AppDomain.CurrentDomain.AssemblyResolve += (s, args) =>
{
var loadedAssembly = System.AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName == args.Name).FirstOrDefault();
if(loadedAssembly != null)
{
return loadedAssembly;
}
if (args.RequestingAssembly == null) return null;
string folderPath = Path.GetDirectoryName(args.RequestingAssembly.Location);
string rawAssemblyPath = Path.Combine(folderPath, new System.Reflection.AssemblyName(args.Name).Name);
string assemblyPath = rawAssemblyPath + ".dll";
if (!File.Exists(assemblyPath))
{
assemblyPath = rawAssemblyPath + ".exe";
if (!File.Exists(assemblyPath)) return null;
}
var assembly = System.Reflection.Assembly.LoadFrom(assemblyPath);
return assembly;
};
- 1. 如何將文件夾添加到給定的Anaconda環境的搜索路徑?
- 2. 在路徑中搜索公用文件夾路徑
- 3. 如何將外部文件夾添加到類路徑中?
- 4. 如何在Texlipse項目中隱藏文件夾「搜索路徑」
- 5. 在Python中加快搜索文件夾路徑?
- 6. 在編譯時將運行時共享庫搜索路徑添加到可執行文件|鏗鏘| Ubuntu
- 7. 添加路徑到Erlang搜索路徑?
- 8. 如何在將第三方庫添加到iPhone應用程序時爲「標題搜索路徑」設置路徑
- 9. 將庫搜索路徑添加到鐺
- 10. 如何將共享庫搜索路徑添加到可執行文件?
- 11. 將文件添加到文件夾時運行MATLAB例程
- 12. .NET程序集如何將引用「翻譯」爲文件路徑?
- 13. 如何在JBoss中添加外部文件夾6類路徑
- 14. 如何將matlab路徑添加到私人文件夾?
- 15. 如何將文件夾添加到您的cmd路徑?
- 16. 在交替路徑中搜索文件
- 17. 如何將.NET程序集添加到InnoSetup中的GAC中?
- 18. 如何在puppet上搜索文件夾路徑?
- 19. 如何檢查一個文件夾是否在搜索路徑
- 20. 在app.config中指定.net程序集綁定/融合的搜索路徑?
- 21. Razor Url.Action將網站文件夾路徑添加到Url中
- 22. 在運行時將包含Java源代碼的文件夾添加到類路徑中
- 23. 如何訪問程序集文件夾中的XML文件的文件路徑?
- 24. 如何將文件夾添加到VSO 2015構建服務器中的搜索路徑
- 25. 如何將.class文件夾添加到eclim中的類路徑中?
- 26. 如何將生成的源文件夾添加到Gradle中的源路徑中?
- 27. 在運行時將圖像添加到drawable- *文件夾
- 28. 在Outlook搜索結果中顯示文件夾路徑
- 29. 遞歸在目錄中搜索所有文件夾路徑
- 30. 如何在代碼中添加dll搜索路徑?
感謝您的補充。我見過很多次的'AssemblyResolve'解決方案,很好有另一個(和更容易)的選項。 – 2015-06-03 15:01:10