DLL của tôi được tải bởi ứng dụng của bên thứ ba mà chúng tôi không thể tùy chỉnh. Hội đồng của tôi phải được đặt trong thư mục riêng của họ. Tôi không thể đưa chúng vào GAC (ứng dụng của tôi có yêu cầu được triển khai bằng XCOPY). Khi DLL gốc cố tải tài nguyên hoặc loại từ một DLL khác (trong cùng một thư mục), tải không thành công (FileNotFound). Có thể thêm thư mục chứa các tệp DLL của tôi vào đường dẫn tìm kiếm lắp ráp theo chương trình (từ gốc DLL) không? Tôi không được phép thay đổi các tập tin cấu hình của ứng dụng.Cách thêm thư mục vào đường dẫn tìm kiếm lắp ráp khi chạy trong .NET?
Trả lời
Bạn có thể thêm probing path vào tệp .config của ứng dụng, nhưng nó sẽ chỉ hoạt động nếu đường dẫn thăm dò nằm trong thư mục cơ sở của ứng dụng của bạn.
Có vẻ như bạn có thể sử dụng sự kiện AppDomain.AssemblyResolve và tải thủ công các phụ thuộc từ thư mục DLL của bạn.
Chỉnh sửa (từ bình luận):
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;
}
Cảm ơn bạn, Mattias! Công trình này: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve + = new ResolveEventHandler (LoadFromSameFolderResolveEventHandler); Tải lắp ráp tĩnhFromSameFolderResolveEventHandler (đối tượng người gửi, ResolveEventArgs args) { thư mục chuỗiPath = Đường dẫn.GetDirectoryName (Assembly.GetExecutingAssembly(). Vị trí); chuỗi assemblyPath = Path.Combine (folderPath, args.Name + ".dll"); Assembly assembly = Assembly.LoadFrom (assemblyPath); lắp ráp trả lại; } – isobretatel
Giải pháp tuyệt vời! Dưới đây là một bài viết mô tả một vài giải pháp khác bao gồm một trong những chi tiết này: http://kbalertz.com/897297/consume-assemblies-located-folder-different-application-folder-Visual-Basic.aspx (cảnh báo: nó cho VB , không phải C# và một chút cũ) – Domenic
Bạn sẽ làm gì nếu bạn muốn "dự phòng" cho Trình giải quyết cơ bản. ví dụ. 'if (! File.Exists (asmPath)) trả về tìm kiếmInGAC (...);' –
nhìn vào AppDomain.AppendPrivatePath (phản đối) hoặc AppDomainSetup.PrivateBinPath
Từ [MSDN] (http://msdn.microsoft.com/en-us/library/system.appdomainsetup.aspx): Thay đổi các thuộc tính của một cá thể AppDomainSetup không ảnh hưởng đến bất kỳ AppDomain hiện có nào. Nó chỉ có thể ảnh hưởng đến việc tạo một AppDomain mới, khi phương thức CreateDomain được gọi với cá thể AppDomainSetup như một tham số. – Nathan
['AppDomain.AppendPrivatePath'] (https://msdn.microsoft.com/en-us/library/system.appdomain.appendprivatepath%28v=vs.110%29.aspx) 's tài liệu hướng dẫn dường như gợi ý rằng nó nên hỗ trợ tự động mở rộng đường dẫn tìm kiếm của 'AppDomain', chỉ là tính năng không còn được dùng nữa. Nếu nó hoạt động, nó là một giải pháp sạch hơn nhiều so với quá tải 'AssemblyResolve'. – binki
Lời giải thích tốt nhất 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' là cho CurrentDomain, không hợp lệ cho một tên miền khác' AppDomain.CreateDomain' – Kiquenet
Cập nhật cho Framework 4
Kể từ khi Khung 4 nâng cao Assembl yResolve sự kiện cũng cho các tài nguyên thực sự xử lý này hoạt động tốt hơn. Nó dựa trên khái niệm rằng bản địa hóa nằm trong thư mục con ứng dụng (một cho bản địa hóa với tên của nền văn hóa nghĩa là C: \ MyApp \ it cho tiếng Ý) Bên trong có tệp tài nguyên. Trình xử lý cũng hoạt động nếu nội địa hóa là quốc gia, tức là it-IT hoặc pt-BR. Trong trường hợp này, trình xử lý "có thể được gọi nhiều lần: một lần cho mỗi văn hóa trong chuỗi dự phòng" [từ MSDN]. Điều này có nghĩa là nếu chúng ta trả về null cho tệp tài nguyên "it-IT", khung công tác sẽ làm tăng sự kiện yêu cầu "nó".
móc Event
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);
Event handler
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;
}
}
Đối với người dùng C++/CLI, đây là câu trả lời @Mattias S'(mà làm việc cho tôi):
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);
tôi đã sử dụng giải pháp @Mattias S '. Nếu bạn thực sự muốn giải quyết các phụ thuộc từ cùng một thư mục - bạn nên thử sử dụng Yêu cầu lắp ráp vị trí, như được hiển thị bên dưới. args.RequestingAssembly cần được kiểm tra về tính rỗng.
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. Thêm thư mục tạm thời vào đường dẫn tìm kiếm DLL của Windows 7
- 2. Thêm thư mục vào đường dẫn tomcat
- 3. Thêm thư mục vào đường dẫn đường dẫn nội dung?
- 4. XCode Thư viện đường dẫn tìm kiếm
- 5. Matplotlib thư mục làm việc latex/đường dẫn tìm kiếm
- 6. Thêm thư mục vào đường dẫn tải trong Rails?
- 7. Chỉ định đường dẫn tìm kiếm cho DllImport trong .NET
- 8. Cách thêm đường dẫn tìm kiếm thư viện được chia sẻ vào tệp thực thi?
- 9. Ubuntu thêm thư mục vào đường dẫn Python
- 10. Đường ống trong lắp ráp
- 11. Thêm thư mục vào đường dẫn của Python vĩnh viễn
- 12. C#: Thư mục lắp ráp tùy chỉnh
- 13. JRuby on Rails: Thêm thư mục vào đường dẫn lớp
- 14. .so đường dẫn tìm kiếm
- 15. Văn hóa lắp ráp .NET là gì?
- 16. Không tìm thấy lắp ráp NUnit
- 17. Maven - Thêm thư mục vào đường dẫn lớp trong khi thực hiện các kiểm tra
- 18. Lắp ráp đường vòng và lắp ráp GCC (Linux)
- 19. dlopen() Đường dẫn tìm kiếm
- 20. Ưu tiên tải lắp ráp .NET
- 21. Lấy đường dẫn của cụm lắp ráp hiện tại
- 22. Cách đặt đường dẫn cho 'Đường dẫn tìm kiếm tiêu đề' khi thêm thư viện của bên thứ 3 vào ứng dụng iPhone
- 23. ComVisible NET lắp ráp và app.config
- 24. Không thể tìm thấy entry trong khi thêm dự án để lắp ráp triển khai
- 25. Lắp ráp Maven: lắp ráp
- 26. x86 lắp ráp hướng dẫn: gọi * Reg
- 27. Hướng dẫn Lắp ráp SPARC
- 28. Lắp ráp ARM - Hướng dẫn chi nhánh
- 29. Ant: Tìm đường dẫn của tệp trong thư mục
- 30. lỗi MSB3216 khi đăng ký lắp ráp
Cảm ơn bạn đã thêm điều này. Tôi đã nhìn thấy các giải pháp 'AssemblyResolve' rất nhiều lần, tốt để có một tùy chọn khác (và dễ dàng hơn). –