Как загрузить сборку во время выполнения перед событием AssemblyResolve?
На самом деле я попытался реализовать какие-то "статически связанные сборки" в моем решении. Поэтому я попробовал следующее:
- Добавление ссылки на мою сборку с помощью CopyLocal = false
- Добавление самого DLL файла в мое решение с помощью "Добавить как ссылку"
- Добавление самого DLL файла в мои ресурсы с помощью "Добавить ресурс" - "Добавить существующий файл"
- Добавление некоторого типа из моей сборки в Form1 как
private MyObject temp = new MyObject();
После этих шагов я получил FileNotFoundException, как и ожидалось. Поэтому попробуйте загрузить сборку в AssemblyResolveEvent с помощью этого быстрого взлома
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
{
Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly);
return MyAssembly;
};
Итак, это работает! Я могу загрузить свою сборку из файла ресурсов в AssemblyResolveEvent. Но это событие происходит только в том случае, если оно не может найти мою сборку нигде. Но как я могу загрузить мою сборку до.Net пытается искать в разных местах?
Из-за фактов из Проверка ранее привязанных сборок я подумал, что можно будет заранее загрузить сборку в домен, и это будет приняты.
Я попробовал это в program.cs с помощью следующего метода Main()
static void Main()
{
LoadMyAssemblies();
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => LoadMyAssemblies();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static Assembly LoadMyAssemblies()
{
Assembly result = AppDomain.CurrentDomain.Load(Properties.Resources.MyStaticAssembly);
return result;
}
Но он все еще попадает в ResolveEventHandler. И гораздо лучше, если я снова загружу сборку и посмотрю на AppDomain.CurrentDomain.GetAssemblies(), я вижу, что моя сборка загружается дважды!
Итак, любая идея, почему моя загруженная сборка не будет учитываться при ее загрузке перед событием AssemblyResolve? С помощью отладчика я также вернул null, когда вызов пришел из AssemblyResolve, но в этом случае я получил исключение FileNotFoundException в начале.
Ответы
Ответ 1
На всякий случай, когда вы не знали, есть инструмент под названием ILMerge из MS Research, который объединяет сборки в один файл.
Также вы можете создавать сборки с несколькими файлами, используя Инструмент компоновщика сборки.
Плюс, чтобы ответить на ваш оригинальный вопрос, проблема в том, что среда выполнения не знает, что сборка, которую вы загрузили вручную, является той, которую она должна искать. Таким образом, в сборке разрешите событие вместо загрузки сборки снова, просто верните ссылку на сборку, которую вы вручную загрузили.
Ответ 2
CLR Binder не знает, что LoadMyAssemblies() делает то же самое, что и событие AssemblyResolve, и что они оба пытаются найти одну и ту же сборку и загрузить ее.
Событие AssemblyResolve всегда запускается в тот момент, когда Binder решает, что он искал все возможные местоположения (которые доступны для поиска по этому приложению) и не смог найти совпадение.
Это вызывает исходный вопрос, а именно, почему вы хотите статически связать свои управляемые сборки? Прочитайте эту тему, чтобы обсудить ее Преимущества статической связи
Я продолжу и отвечу на вопрос о том, как избежать участия в событии AssemblyResolve
1) Поместите сборку в GAC. Что касается Binder, то GAC всегда выигрывает.
2) Поместите свою сборку на пробный путь и убедитесь, что Binder ее подбирает (посмотрите на статью "Как среда выполнения находит сборки" в MSDN для получения дополнительной информации об этом).