Я хочу загрузить новую AppDomain
сборку со сложным деревом ссылок (MyDll.dll -> Microsoft.Office.Interop.Excel.dll -> Microsoft.Vbe.Interop.dll -> Office.dll -> stdole.dll)
Насколько я понял, когда сборка загружается AppDomain
, ее ссылки не загружаются автоматически, и мне приходится загружать их вручную. Итак, когда я это сделаю:
string dir = @"SomePath"; // different from AppDomain.CurrentDomain.BaseDirectory
string path = System.IO.Path.Combine(dir, "MyDll.dll");
AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = dir;
AppDomain domain = AppDomain.CreateDomain("SomeAppDomain", null, setup);
domain.Load(AssemblyName.GetAssemblyName(path));
и получил FileNotFoundException
:
Не удалось загрузить файл или сборку MyDll, Version = 1.0.0.0, Culture = нейтральный, PublicKeyToken = null или одну из их зависимостей. Система не может найти указанный файл.
Я думаю, что ключевая часть - это одна из его зависимостей .
Хорошо, я сделаю следующий раньше domain.Load(AssemblyName.GetAssemblyName(path));
foreach (AssemblyName refAsmName in Assembly.ReflectionOnlyLoadFrom(path).GetReferencedAssemblies())
{
domain.Load(refAsmName);
}
Но попал FileNotFoundException
снова, на другой (упомянутой) сборке.
Как загрузить все ссылки рекурсивно?
Нужно ли создавать дерево ссылок перед загрузкой корневой сборки? Как получить ссылки на сборку, не загружая ее?
источник
Ответы:
Вы должны вызвать его
CreateInstanceAndUnwrap
до того, как ваш прокси-объект будет выполняться в домене стороннего приложения.Также обратите внимание, что при использовании
LoadFrom
вы, скорее всего, получитеFileNotFound
исключение, потому что распознаватель сборок попытается найти сборку, которую вы загружаете, в GAC или в папке bin текущего приложения.LoadFile
Вместо этого используйте для загрузки произвольного файла сборки, но обратите внимание, что если вы это сделаете, вам придется загружать любые зависимости самостоятельно.источник
AppDomain.CurrentDomain.AssemblyResolve
событию, как описано в этом ответе MSDN . В моем случае я пытался подключиться к развертыванию SpecRun, работающему под MSTest, но я думаю, что это применимо ко многим ситуациям, в которых ваш код может не запускаться из «основного» домена приложения - расширения VS, MSTest и т. Д.assembly
переменная будет ссылаться на сборку из "MyDomain"? Я думаю,var assembly = value.GetAssembly(args[0]);
вы загрузите ваш файлargs[0]
в оба домена, иassembly
переменная будет ссылаться на копию из основного домена приложенияhttp://support.microsoft.com/kb/837908/en-us
Версия C #:
Создайте класс модератора и унаследуйте его от
MarshalByRefObject
:звонок с сайта клиента
источник
MarshalByRefObject
можно передавать по доменам приложений. Поэтому я бы предположил, что онAssembly.LoadFrom
пытается загрузить сборку в новый домен приложения, что возможно только в том случае, если вызывающий объект может быть передан между этими доменами приложений. Это также называется удаленнымMarshalByRefObject
не волшебным образом заставляет его загружаться во всех другихAppDomain
, оно просто сообщает платформе .NET создать прозрачный прокси удаленного взаимодействия вместо использования сериализации, когда вы разворачиваете ссылку из одногоAppDomain
в другойAppDomain
(типичный способ - этоCreateInstanceAndUnwrap
метод). Не могу поверить, что у этого ответа более 30 голосов; код здесь просто бессмысленно обходной способ вызоваAssembly.LoadFrom
.Как только вы передадите экземпляр сборки обратно в вызывающий домен, вызывающий домен попытается загрузить его! Вот почему вы получаете исключение. Это происходит в вашей последней строке кода:
Таким образом, все, что вы хотите сделать со сборкой, следует делать в прокси-классе - классе, который наследует MarshalByRefObject .
Примите во внимание, что и вызывающий домен, и новый созданный домен должны иметь доступ к сборке прокси-класса. Если ваша проблема не слишком сложна, подумайте о том, чтобы оставить папку ApplicationBase без изменений, чтобы она была такой же, как и папка домена вызывающего абонента (новый домен будет загружать только необходимые ему сборки).
В простом коде:
Если вам действительно нужно загрузить сборки из папки, которая отличается от текущей папки домена приложения, создайте новый домен приложения с определенной папкой пути поиска dll.
Например, строку создания домена приложения из приведенного выше кода следует заменить на:
Таким образом, все библиотеки DLL будут автоматически разрешены из dllsSearchPath.
источник
В своем новом домене приложений попробуйте установить обработчик событий AssemblyResolve . Это событие вызывается, когда зависимость отсутствует.
источник
Вам необходимо обработать события AppDomain.AssemblyResolve или AppDomain.ReflectionOnlyAssemblyResolve (в зависимости от того, какую нагрузку вы выполняете), если указанная сборка не находится в GAC или на пути проверки CLR.
AppDomain.AssemblyResolve
AppDomain.ReflectionOnlyAssemblyResolve
источник
Мне потребовалось время, чтобы понять ответ @ user1996230, поэтому я решил привести более подробный пример. В приведенном ниже примере я создаю прокси для объекта, загруженного в другом домене приложения, и вызываю метод этого объекта из другого домена.
источник
Ключ - это событие AssemblyResolve, вызванное AppDomain.
источник
Мне приходилось делать это несколько раз, и я исследовал множество различных решений.
Решение, которое я нахожу наиболее элегантным и легким в реализации, может быть реализовано как таковое.
1. Создайте проект, в котором можно создать простой интерфейс.
интерфейс будет содержать подписи всех участников, которым вы хотите позвонить.
Важно, чтобы этот проект был чистым и легким. Это проект, на который
AppDomain
могут ссылаться оба, и который позволит нам не ссылаться наAssembly
мы хотим загрузить в отдельный домен из нашей клиентской сборки.2. Теперь создайте проект с кодом, который вы хотите загрузить отдельно.
AppDomain
.Этот проект, как и клиентский, будет ссылаться на прокси-сервер, и вы реализуете интерфейс.
3. Затем в клиентском проекте загрузите код в другой
AppDomain
.Итак, теперь мы создаем новый
AppDomain
. Можно указать базовое расположение для ссылок на сборки. Зондирование проверит наличие зависимых сборок в GAC, в текущем каталоге и вAppDomain
базовом местоположении.если вам нужно, существует масса различных способов загрузить сборку. С этим решением вы можете использовать другой способ. Если у вас есть полное имя сборки, мне нравится использовать,
CreateInstanceAndUnwrap
поскольку он загружает байты сборки, а затем создает для вас экземпляр вашего типа и возвращает то,object
что вы можете просто преобразовать в свой тип прокси или, если вы этого не сделаете, в строго типизированный код, который вы могли бы используйте среду выполнения динамического языка и назначьте возвращаемый объектdynamic
типизированной переменной, а затем просто вызовите элементы для этого напрямую.Вот и все.
Это позволяет загрузить сборку, на которую ваш клиентский проект не ссылается, в отдельном
AppDomain
и вызывать ее элементы из клиента.Для тестирования мне нравится использовать окно «Модули» в Visual Studio. Он покажет вам домен вашей клиентской сборки и все модули, загруженные в этом домене, а также ваш новый домен приложения и какие сборки или модули загружены в этом домене.
Главное - убедиться, что код является производным
MarshalByRefObject
или сериализуемым.`MarshalByRefObject позволит вам настроить время жизни домена, в котором он находится. Например, вы хотите, чтобы домен был уничтожен, если прокси не был вызван в течение 20 минут.
Надеюсь, это поможет.
источник
Foo, FooAssembly
который имеет свойство типаBar, BarAssembly
, т.е. всего 3 сборки. Будет ли он продолжать работать?