Есть приложение. Оно ищет свои плагины в папке /modules/
Там лежат библиотеки (А), определяемые общим интерфейсом.
Так же эти библиотеки имеют референсы на какие-то третьи библиотеки (Б), которые лежат рядом с ними. т.е. в папке /modules/.
Получается следующая схема:
App -> [inteface] -> dll А -> [reference] -> dll Б
При попытке вызвать из приложения метод из А, в котором есть ссылка на Б (по референсу, соответственно) появляется сообщение об ошибке, что библиотека Б не найдена! (ибо она ищется в папке с приложением а не в папке с библиотекой, которой её вызывает)
Вопрос: как указать приложению дополнительный путь для поиска указанных в референсе библиотек?
У меня сложилось впечатление, что причина этой проблемы в том, что референс указывается не по пути к файлу, а по имени библиотеки (MyLib, Version=1.0.1.0 Culture=neutral, PublicToken=a1b2c3d4e5)
И поиск происходит либо в AppBase (он же StartupPath, карчое ппака приложения) либо в GAC'е — если ни там ни там файла нет — выдаётся ошибка FileNotFound! Что делать?
Иногда возникает задача перехватить стандартную загрузку модулей и загрузть модуль, лежащий в определенной папке. Например, при решении проблемы локализации приложений, ресурсы могут лежать по папкам с именами языка и в зависимости от выбранного языка нужно загружать соответствующий модуль. Аналогичная задача может возникнуть при поиске модуля, содержащего нужный тип.
Событие AppDomain.CurrentDomain.TypeResolve вызывается, если системе (точнее говоря текущему домену) не удалось найти сборку, содержащую запрошенный тип. Событие AppDomain.CurrentDomain.AssemblyResolve вызывается, если системе не удалось найти запрошенную сборку.
Листинг 23 показывает пример использования этих событий. Главный модуль MainClass использует две сборки: ClassLibrary1, содержащую класс Class1 и ClassLibrary2, содержащую класс Class2. Главный модуль не имеет ссылки на первую сборку, поэтому при попытке найти тип Class1 будет вызываться обработчик TypeResolve, в котором мы загрузим нужную сборку самостоятельно. На вторую сборку ссылка имеется, но у нее выставлен тип CopyLocal=False, поэтому система не сможет определить местонахождение сборки и вызовет обработчик AssemblyResolve, в котором мы загрузим эту сборку самостоятельно.
Листинг 23. Трассировка исключенияОбработка событий AssemblyResolve и TypeResolve
using System;
using System.Reflection;
namespace ResolveAssembly
{
class MainClass
{
static MainClass()
{
AppDomain.CurrentDomain.TypeResolve +=
new ResolveEventHandler(CurrentDomain_TypeResolve);
AppDomain.CurrentDomain.AssemblyResolve +=
new ResolveEventHandler(currentDomain_AssemblyResolve);
}
[STAThread]
static void Main(string[] args)
{
Type t = Type.GetType("ClassLibrary1.Class1", false);
if (t != null)
{
Console.WriteLine(t.Name);
}
else
{
Console.WriteLine("Тип не найден");
}
ClassLibrary2.Class2 c2 = new ClassLibrary2.Class2();
Console.WriteLine(c2.ToString());
}
private static Assembly CurrentDomain_TypeResolve(
object sender, ResolveEventArgs args)
{
Console.WriteLine("Ищу тип: {0}...", args.Name);
if (args.Name.Equals("ClassLibrary1.Class1"))
{
return Assembly.LoadFrom(
@"..\ClassLibrary1\bin\ClassLibrary1.dll");
}
return null;
}
private static Assembly currentDomain_AssemblyResolve(
object sender, ResolveEventArgs args)
{
Console.WriteLine("Ищу сборку {0}...", args.Name);
if (args.Name.IndexOf("ClassLibrary2") >= 0)
{
return Assembly.LoadFrom(
@"..\ClassLibrary2\bin\ClassLibrary2.dll");
}
return null;
}
}
}
P_A>55. Перехват загрузки типов и модулей
P_A>Иногда возникает задача перехватить стандартную загрузку модулей и загрузть модуль, лежащий в определенной папке. Например, при решении проблемы локализации приложений, ресурсы могут лежать по папкам с именами языка и в зависимости от выбранного языка нужно загружать соответствующий модуль. Аналогичная задача может возникнуть при поиске модуля, содержащего нужный тип. P_A>Событие AppDomain.CurrentDomain.TypeResolve вызывается, если системе (точнее говоря текущему домену) не удалось найти сборку, содержащую запрошенный тип. Событие AppDomain.CurrentDomain.AssemblyResolve вызывается, если системе не удалось найти запрошенную сборку. P_A>Листинг 23 показывает пример использования этих событий. Главный модуль MainClass использует две сборки: ClassLibrary1, содержащую класс Class1 и ClassLibrary2, содержащую класс Class2. Главный модуль не имеет ссылки на первую сборку, поэтому при попытке найти тип Class1 будет вызываться обработчик TypeResolve, в котором мы загрузим нужную сборку самостоятельно. На вторую сборку ссылка имеется, но у нее выставлен тип CopyLocal=False, поэтому система не сможет определить местонахождение сборки и вызовет обработчик AssemblyResolve, в котором мы загрузим эту сборку самостоятельно.
спасибо большое!!
я пробовал
Assembly my = Assembly.GetEntryAssembly();
my.ModuleResolve += new ResolveEventHandler(ModuleResolve);
спасибо! буду знать. я читал в MSDN'е про probing, но ничего не понял, больно сумбурно, на мой взгляд, там это описано..
+ в моём случае решение проблемы кодом, мне кажется, больше подходит, т.к. у меня не WinApp, у которого все пути практически фиксированы, и в конфиг можно дописать, к примеру, /plugins
а библитека-диспетчер модулей для очень гибкого ядра CMS. там всё столь динамично настраивается, что конфиг, боюсь, не подойдёт.
Здравствуйте, abatishchev, Вы писали:
A>а библитека-диспетчер модулей для очень гибкого ядра CMS. там всё столь динамично настраивается, что конфиг, боюсь, не подойдёт.
Трудно представить приложение для которого не подойдет конфиг...
Хочу обратить внимание на один момент. Корень проблемы кроется в том, что модуль-пагин тянет за собой рефренсы на какие-то третьи сборки. Это проблема архитектуры. Подключаемые модули обычно выполняются как реализация интерфейсов, объявленных в базовой системе. Поэтому в них достаточно ссылок на сборки базовой системы и общие сборки .Net. Если же модуль тянет за собой дюжину других сборок то это уже не плагин, и для его реализации нужно использовать другие подходы. Например "Реестр сервисов" — "Провайдер сервиса" как это принято в SOA.
Здравствуйте, stump, Вы писали:
S>Трудно представить приложение для которого не подойдет конфиг... S>Хочу обратить внимание на один момент. Корень проблемы кроется в том, что модуль-пагин тянет за собой рефренсы на какие-то третьи сборки. Это проблема архитектуры. Подключаемые модули обычно выполняются как реализация интерфейсов, объявленных в базовой системе. Поэтому в них достаточно ссылок на сборки базовой системы и общие сборки .Net. Если же модуль тянет за собой дюжину других сборок то это уже не плагин, и для его реализации нужно использовать другие подходы. Например "Реестр сервисов" — "Провайдер сервиса" как это принято в SOA.
не обязательно, что модуль-плагин тянет дюжину референсов! хотя бы 1. к примеру, SSL- или JPEG-библиотеку, что угодно! получается, что плагин должен содержать только собственноручно писанный код, и ничего более. хорошо если есть такая возможность. а если нужно хоть что-то зацепить извне — вся архитектура рушится.. а это полная Ж.