|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
Здравствуйте, хотел обратиться к Вам со следующей проблемой. Генерирую две сборки с помощью встроенного C# компилятора кода. Первая запускаемая, а вторая с так называемыми вспомогательными пользовательскими функциями. Проблема именно в том, чтобы загрузить их одновременно в домен, для возможности дальнейшей выгрузки, т.к. загруженную сборку можно выгрузить лишь выгрузив её домен. Загрузка сборок должна производиться из определенного каталога, который не связан с приложением (Допустим C:\Libraries). В этом главная проблема, потому что если положить сборки в каталог запускаемого приложения, то все загружается легко. Запускаемая библиотека: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Код: plaintext 1. 2. 3. 4. 5. 6.
Перепробовал не мало способов, и мои пояснения. Поправьте, если я не прав. Загрузка в текущий домен, что изначально не подходит, но все же привел его. Как я понял данным метод загружается вне контекста, где дополнительно невозможно загружать другие сборки Код: plaintext
Подписываюсь на событие при невозможности загрузки из каталога приложения. Обманный ход, но не работает. Код: plaintext 1. 2. 3.
Метод Invoke я произвожу поиск класса и его метода по сборке и потом запускаю. Что то вроде этого Код: plaintext
Метод CreateInstanceFromAndUnwrap. Как я понял, то необходимо объявлять через интерфейс, наследоваться от MarshalByRefObject и применение флага [Serializable]. Это работает, но жутко не удобно, потому что в реальном приложении объявления этого флага [Serializable] необходимо у 90% всех классов! o_O Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Пробовал и с применением класса AppDomainSetup, в котором можно указать ApplicationBase - каталог с приложением, а именно там сначала проводится поиск необходимых сборок. Но как будто он не реагирует на это поле. Вот мой тестовый проект. http://depositfiles.com/files/25mk9qtff ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 10:31 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, Для поиска сборок: Код: plaintext 1. 2. 3. 4. 5.
Для проброски ссылок через домен можно использовать интерфейсы и MarshalByRefObject. Для указания того, в какие домены будет загружена сборка существует 2 способа: Настройка m_Setup.LoaderOptimization при создании домена, а также установка атрибута LoaderOptimization методу Main в основном домене. Подробнее про LoaderOptimization очень хорошо написано в MSDN. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 10:46 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, 1. читаем файл в массив байт 2. грузим массив в домен, c помощью Load ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 11:38 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
tAZAR... Чтобы использовать MarshalByRefObject, как я понимаю, необходимо чтобы все входные параметры были Serializable. Что описано в одном из моем подходе. [quot pation]... 2kКак я понял данным метод загружается вне контекста, где дополнительно невозможно загружать другие сборки То есть, загрузка просто загрузчика пройдет, но если в будет необходима ссылка на вторую библиотеку, то её попросту не найдет. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 11:57 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, Если я правильно вас понял: При использовании MarshalByRefObject ссылка на него пробрасывается как TransparentProxy. Serializable не нужен. Если вы о параметрах, передаваемых в его методы - то потребуется либо наследовать их от MarshalByRefObject, либо метить как Serializable, да. А с загрузкой сборок PrivateBinPath, надеюсь, помог. Есть еще 1 нюанс - при загрузке сборки в домен она грузится и в основной домен приложения тоже (по умолчанию). Спасает DoCallBack у домена и вызов Assembly.Load. Сам давно посматриваю в сторону MEF, где есть гора фенечек, время бы найти.. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 12:19 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
tAZAR2k, Если я правильно вас понял: При использовании MarshalByRefObject ссылка на него пробрасывается как TransparentProxy. Serializable не нужен. Если вы о параметрах, передаваемых в его методы - то потребуется либо наследовать их от MarshalByRefObject, либо метить как Serializable, да. Да правильно. Но тут вытекает следующее - передаваемый параметр не примитив, следовательно все ссылки на не примитивные классы в нем тоже необходимо пометить Serializable или наследовать от MarshalByRefObject. Это своего рода костыль, простите. tAZARА с загрузкой сборок PrivateBinPath, надеюсь, помог. Есть еще 1 нюанс - при загрузке сборки в домен она грузится и в основной домен приложения тоже (по умолчанию). Спасает DoCallBack у домена и вызов Assembly.Load. Честно говоря у меня так и не получилось это. Указываю ApplicationBase, в документации MSDN было написано, что PrivateBinPath относительно его указывается. Пробовал и так и так. =`( ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 12:35 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, Вот пример поподробнее: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.
Дело в том, что домены обмениваются информацией при помощи механизмов Remoting (через прокси и сериализация), поэтому вряд ли получится найти что-то новое. Есть еще AppDomain.SetData, но там те же грабли. Кстати, проблему перезагрузки сборок также можно решить, включив у домена теневое копирование, вкрутив IoC и используя загрузку сборок через массивы. В принципе, даже без доменов. Выгрузки не будет, больная это тема в дотнете... ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 12:59 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
tAZAR, Вообщем делаю так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Пробовал и сразу ApplicationBase указывать на dir_dll, тогда PrivateBinPath = "". Эффекта не было. Что я делаю не так? ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 14:32 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2kЧто я делаю не так? Не указываете полный путь к каталогам в PrivateBinPath, не указываете путь к базовому каталогу основного домена (если нужен). С AppDomain.Load есть проблемы - как не бейся, грузит в оба домена. Спасает DoCallback. Код: plaintext 1.
Если указан PrivateBinPath, PrivateBinPathProbe должен быть "". Нужен фабричный метод или прокси для создания типов из загруженной сборки в нужном домене. Помогает написание своей обертки над доменом, загрузка, повторюсь, через DoCallback (суть в том, чтобы выполнить код и загрузку сборки именно в том домене, который вам нужен). ... |
|||
:
Нравится:
Не нравится:
|
|||
18.10.2011, 14:58 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
MSDNЕсли заданные для PrivateBinPath каталоги не находятся в папке ApplicationBase, они игнорируются. Я попытался сделать обертку, вот что получилось: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20.
Но ловлю ошибку, которую не могу осмыслить: Тип "TestInvoke.ARMDomain+<>c__DisplayClass1" сборки "TestInvoke, Version=1.0.0.2, Culture=neutral, PublicKeyToken=null" не помечен как сериализуемый. Хотя без обертки библиотека загружается, но возвратить Assembly не могу. ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 11:51 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, А сборку и ненужно возвращать, иначе пропадает смысл домена. (Сборка вместе с ее типами загрузится и туда, куда вы ее вернете). Вот вам пример, давно его здесь выкладывал. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59.
Нужно внимательно следить за контекстами работы кода (легко, например, случайно вернуть тип в основной домен, вызвав метод GetType у ссылки на прокси или посмотрев значения переменных в отладчике). Если вам требуется создавать экземпляры объектов плагина в основном домене - сделайте обертке специальный метод, который будет создавать экземпляр и верните известный обоим доменам интерфейс. Иначе объект распакуется и тип будет загружен. Единственный способ выполнить код в определенном домене - вызов через DoCallback. ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 12:05 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
А вот пример работы с доменами и фабрикой, работающей в создаваемых доменах, тоже давно здесь выкладывал. Похожая тема была, кстати :) Там в папке с тестом должен быть файл "file.txt". Иначе упадет, кажется. ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 12:13 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
tAZARА вот пример работы с доменами и фабрикой, работающей в создаваемых доменах, тоже давно здесь выкладывал. Похожая тема была, кстати :) Там в папке с тестом должен быть файл "file.txt". Иначе упадет, кажется. Кстати на днях разбирал этот пример. Там все замечательно работает вот по этой строчке: Код: plaintext
Код: plaintext
С вашим примером сейчас разбираюсь. ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 12:51 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, В прикрепленном в архиве примере у меня суть в том, что фабрика создается внутри отдельного домена (в него же и загружаются сборки). Создает экземпляры классов она тоже внутри контекста выполнения отдельного домена, а ссылки уже возвращает наружу. AppDomain.CurrentDomain в фабрике используется, т.к. есть уверенность, что текущий домен для фабрики - тот самый новый домен. По консольному выводу это будет видно, также как и будет видно отсутствие множественной загрузки сборок во все домены приложения. Пример с CodeDom показыват, что сборка создается также в нужном домене. ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 13:09 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
tAZAR, При загрузке CreateInstanceFromAndUnwrap, то в качестве входных параметров для реализуемого в плагине сборке методу необходимо передавать только сериализуемые или наследуемые от MarshalByRefObject объекты. Один из объектов содержит экземпляр системного класса, который не сериализуемый (System.IO.BinaryReader). Тупик. =) ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 15:00 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2k, Оборачивайте BinaryReader и все, что не унаследовано от MarshalByRefObject, либо не сериализуется в свои заместители/прокси объекты, унаследованные от MarshalByRefObject. Здесь нужно определиться - будете ли вы передавать копии объектов, либо вам нужны разделяемые между доменами экземпляры. Я уже писал, что домены работают через Remoting. А там либо прокси (маршаллинг), либо сериализация. Еще 1 путь взаимодействия между доменами - контракты, WCF. С пушки по воробьям. Микрософт в 2004 году писал в одном из ответов на тему выгрузки сборок, что они планируют ее реализовать в следующих версиях. Вот уже 2011й наступил, а у нас все те же домены, костыли и сожранная под них память... ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 15:20 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
Кстати, пробросить таким способом поток - цель смутно мне понятная (тем более, через сериализацию) :) Достаточно прокси к потоку в основном домене и возможности работать с этим экземпляром во втором домене - 100%. Либо передавайте содержимое потока как массив, если достаточно копии (+съеденная память). При работе с доменами приходится немного по другому думать, и способы с простой передачей объекта, содержащего "все что нужно", не прокатывают. ... |
|||
:
Нравится:
Не нравится:
|
|||
19.10.2011, 15:29 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
Действительно было не логично передавать объект, содержащего "все что нужно". Сделал реорганизацию по разделению модели и её заполнение. Но вот одно я перенести не смог. Я в качестве параметра передаю ссылку на метод, так называемый "call back". Как мне это абстрагировать, ума не приложу. :) ... |
|||
:
Нравится:
Не нравится:
|
|||
20.10.2011, 13:04 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
Вообщем решил просто отказаться от call back. Так что проблема решена. Огромное спасибо tAZAR. ... |
|||
:
Нравится:
Не нравится:
|
|||
20.10.2011, 14:25 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
Все же одна проблема возникла. Загрузка через AppDomain.CreateInstanceFromAndUnwrap занимает огромное количество времени (я так понимаю это в связи с сериализацией объектов), в отличии от Assembly.LoadFrom. Все бы хорошо, если бы при LoadFrom не блокировался файл. ... |
|||
:
Нравится:
Не нравится:
|
|||
21.10.2011, 15:09 |
|
Загрузка сборки в домен из произвольного каталога
|
|||
---|---|---|---|
#18+
2kВообщем решил просто отказаться от call back. Так что проблема решена. Огромное спасибо tAZAR. Скажи пожалуйста, как решил проблему? а то че-то никак не въеду сто делать с этими доменами... ( ... |
|||
:
Нравится:
Не нравится:
|
|||
25.12.2013, 17:30 |
|
|
start [/forum/topic.php?fid=20&msg=37489082&tid=1403465]: |
0ms |
get settings: |
10ms |
get forum list: |
13ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
68ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
53ms |
get tp. blocked users: |
1ms |
others: | 336ms |
total: | 499ms |
0 / 0 |