Странное поведение при смешивании загрузки сборок с использованием Assembly.LoadFrom и Assembly.Load - PullRequest
5 голосов
/ 06 января 2009

Странное поведение при смешивании загрузки сборок с использованием Assembly.LoadFrom и Assembly.Load

Я столкнулся со странным поведением при загрузке сборок с Assembly.LoadFrom и позже с Assembly.Load.
Я загружаю сборку, используя Assembly.LoadFrom, где сборка находится в папке, которая не является папкой выполнения.

Позже в моем тестовом коде, когда я снова пытаюсь загрузить эту сборку с Assembly.Load, происходит сбой загрузки с System.IO.FileNotFoundException («Не удалось загрузить файл или сборку…»), несмотря на то, что сборка уже загружен. Загрузка завершается неудачно как со строгим именем, так и с не строгим именем (первоначальная причина повторной загрузки этой сборки - использование BinaryFormatter).

Однако, если сборка находится в папке выполнения, последующая загрузка будет успешной в обоих случаях со строгим именем и не строгим именем. В этом случае вы можете видеть, что две идентичные сборки загружаются из двух разных мест.

Простой пример кода, воссоздающий эту проблему -

Сборка сборки1 = Assembly.LoadFrom (@ "C: \ a.dll");

// Сбой при загрузке со строгим именем Assembly Assembly2 = Assembly.Load (@ "a, Версия = 1.0.0.0, Культура = нейтральная, PublicKeyToken = 14986c3f172d1c2c ");

// Также загрузка с не сильным сбоем Assembly Assembly3 = Assembly.Load (@ "a");

  1. Любое объяснение, почему CLR игнорирует уже загруженную сборку?
  2. Есть идеи, как мне решить эту проблему?

Спасибо.

Ответы [ 2 ]

9 голосов
/ 06 января 2009

Это не странно. Согласно документации, загрузка с помощью Load и LoadFrom поместит сборки в разные контексты. Это может помочь.

  1. Любое объяснение, почему CLR игнорирует уже загруженную сборку?

Потому что они в другом контексте.

  1. Есть идеи, как мне решить эту проблему?

Загрузите из того же контекста или помогите 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>

http://msdn.microsoft.com/en-us/library/823z9h8w.aspx

7 голосов
/ 06 января 2009

@ Кент Бугарт: Это, кажется, правильное объяснение. Для полного объяснения у Сюзанны Кук есть эта запись в блоге, которая содержит немного больше, чем оригинал, который вы опубликовали: 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;
 }
...