Как динамически загрузить сборку из пользовательского каталога, включая его зависимости?
Я нашел следующий код, который динамически загружает dll из пользовательского местоположения:
private void Form1_Load(object sender, EventArgs e)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
}
private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string assemblyPath = Path.Combine(folderPath, "libs", new AssemblyName(args.Name).Name + ".dll");
if (File.Exists(assemblyPath) == false) return null;
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
private void button1_Click(object sender, EventArgs e)
{
var zip = ZipFile.Read("test.zip");
foreach (ZipEntry file in zip)
{
file.Extract(".", ExtractExistingFileAction.OverwriteSilently);
}
}
В некоторых случаях это решение работает, но с dll ZipDotNet я получаю:
InnerException {"File or assembly name \"Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c\" or one of its dependencies, was not found. Operation is not supported. (Exception from HRESULT: 0x80131515)":"Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c"} System.Exception {System.IO.FileLoadException}
С момента его прохождения if (File.Exists(assemblyPath) == false) return null;
Я предполагаю, что это проблема с загрузкой зависимостей Ionic.Zip.dll? Как бы я их разрешил?
1 ответ
Глядя на исходный код Iconic.Zip.dll здесь, я вижу, что единственными ссылками в проекте являются System, System.Data, System.Security и System.Xml, поэтому я сомневаюсь, что причина в том, что вы не можете загрузить любую из своих ссылок.
Я думаю, что ваш метод разрешения сборки слишком прост. Предполагается, что имя сборки совпадает с именем файла, что не всегда так. Так что вы можете сделать, это получить AssemblyName
для каждой библиотеки в целевой папке и сохранить сопоставление имен с файлами. Затем, когда распознаватель запрашивает имя, вы ищите его в известных именах и загружаете файл сборки. Вот быстрая реализация идеи.
private Dictionary<string, string> assemblyNameToFileMapping = new Dictionary<string, string>();
private void Form1_Load(object sender, EventArgs e)
{
GetAssemblyNames();
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
}
private void GetAssemblyNames()
{
string folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "libs");
foreach(string file in Directory.EnumerateFiles(folderPath, "*.dll"))
{
try
{
AssemblyName name = AssemblyName.GetAssemblyName(file);
assemblyNameToFileMapping.Add(name.FullName, file);
}
catch { } // Just move on if we can't get the name.
}
}
private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
string file;
if (assemblyNameToFileMapping.TryGetValue(args.Name, out file))
{
return Assembly.LoadFrom(file);
}
return null;
}