Странное поведение при смешивании загрузки сборок с использованием Assembly.LoadFrom и Assembly.Load
Странное поведение при смешивании загрузки сборок с использованием Assembly.LoadFrom и Assembly.Load
Я столкнулся со странным поведением при загрузке сборок с Assembly.LoadFrom и позже с Assembly.Load.
Я загружаю сборку, используя Assembly.LoadFrom, где сборка находится в папке, которая не является папкой выполнения.
Позже в моем тестовом коде, когда я пытаюсь снова загрузить эту сборку с Assembly.Load, загрузка завершается с ошибкой System.IO.FileNotFoundException ("Не удалось загрузить файл или сборку…"), несмотря на то, что сборка уже загружена, Загрузка завершается неудачно как со строгим именем, так и с не строгим именем (первоначальная причина повторной загрузки этой сборки - использование BinaryFormatter).
Однако, если сборка находится в папке выполнения, последующая загрузка завершается успешно в обоих случаях со строгим именем и не строгим именем. В этом случае вы можете видеть, что две идентичные сборки загружаются из двух разных мест.
Простой пример кода, воссоздающий эту проблему -
Assembly Assembly1 = Assembly.LoadFrom (@ "C: \ a.dll");
// Сбой при загрузке со строгим именем Assembly Assembly2 = Assembly.Load(@"a, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken = 14986c3f172d1c2c");
// Также загрузка с не сильным сбоем Assembly Assembly3 = Assembly.Load(@"a");
- Любое объяснение, почему CLR игнорирует уже загруженную сборку?
- Любая идея, как я могу облегчить эту проблему?
Благодарю.
2 ответа
Это не странно. Согласно документации, загрузка с помощью Load и LoadFrom поместит сборки в разные контексты. Это может помочь.
- Любое объяснение, почему CLR игнорирует уже загруженную сборку?
Потому что они в другом контексте.
- Любая идея, как я могу облегчить эту проблему?
Загрузите из того же контекста или помогите CLR найти сборку, возможно, подключив обработчик к AppDomain.AssemblyResolve
,
альтернатива
Если место, из которого вы загружаете сборки, является подпапкой в AppDomain.BaseDirectory, вы можете просто добавить запись в свой App.config:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>
@Kent Boogart: похоже, это правильное объяснение. Для полного объяснения у Сюзанны Кук есть эта запись в блоге, которая содержит чуть больше, чем оригинал, который вы опубликовали: http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx
Ниже приведен код с использованием AppDomain.AssemblyResolve -
// register to listen to all assembly resolving attempts:
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
// Check whether the desired assembly is already loaded
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) {
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies) {
AssemblyName assemblyName = assembly.GetName();
string desiredAssmebly = args.Name;
if (assemblyName.FullName == desiredAssmebly) {
return assembly;
}
}
// Failed to find the desired assembly
return null;
}