На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> Run-time загрузка, пересборка библиотек
    Столкнулся с проблемой.
    Библиотеки написаны на c#. Первую библиотеку, библиотеку1, подключаю из c++ проекта (run-time - это когда запущен этот проект). Охота из dll в run-time (т.е. когда ее используют) подключить другую библиотеку, библиотеку2, (тоже c#) и поюзать ее методы.
    При этом ставится еще одно условие! Что бы не останавливая run-time проекта пересобирать библиотеку2.
    Как это сделать?
      Цитата

      Охота из dll в run-time (т.е. когда ее используют) подключить другую библиотеку, библиотеку2, (тоже c#) и поюзать ее методы.

      В .NET лучше ссылку добавить в reference сборки, чтобы подгрузилась при загрузке. Зачем тебе в рантайм? Память экономишь? Забудь, та же ХР скажем все равно это закеширует в каком-нить Prefetch и ничего ты не выиграешь. LoadLibrary это вчерашний день.
      Цитата

      При этом ставится еще одно условие! Что бы не останавливая run-time проекта пересобирать библиотеку2.
      Как это сделать?

      Тут я тебя не понял
        Как раз хочу обойтись без reference.
        К примеру, я передаю методу из dll имя библиотеки, которую надо загрузить и выполнить метод, имя которого я знаю. При этом имя может быть произвольное, да и в следующем вызове, та же самая библиотека может быть пересобрана (между вызовами).
        А LoadLibrary - в c# нету. Или я ошибаюсь?
          Цитата DarkKo, 15.09.03, 11:06:44
          Как раз хочу обойтись без reference.
          К примеру, я передаю методу из dll имя библиотеки, которую надо загрузить и выполнить метод, имя которого я знаю.

          Такие вещи делаются через рефлекшн. смотри Activator. Загружаешь нужный тебе тип и вызываешь нужный метод (Invoke)
          Цитата

          При этом имя может быть произвольное, да и в следующем вызове, та же самая библиотека может быть пересобрана (между вызовами).
          А LoadLibrary - в c# нету. Или я ошибаюсь?

          Assembly.LoadFrom или Assembly.LoadWithPartialName
          Сообщение отредактировано: kl -
            Загрузить библиотеку получилось!
            Спасибо!
            ExpandedWrap disabled
              <br>Assembly SecondScriptAssembly;<br>SecondScriptAssembly = Assembly.LoadFrom("...\\dinamo.dll");<br>Object fromdll = SecondScriptAssembly.CreateInstance("dinamo.PrintMessage");<br>MethodInfo Method;<br>Method = SecondScriptAssembly.GetTypes()[0].GetMethod("Message");<br>Object [] paramasa = new object[1];<br>paramasa[0] = "Importede string\n";<br>Method.Invoke(fromdll,paramasa);<br>


            А вот как теперь ее выгрузить, что бы пересобрать, например? Т.е. что бы эта dinamo.dll освободилась!
              Цитата DarkKo, 15.09.03, 12:58:56
              Загрузить библиотеку получилось!
              Спасибо!
              ExpandedWrap disabled
                <br>... skipped...<br>

              А вот как теперь ее выгрузить, что бы пересобрать, например? Т.е. что бы эта dinamo.dll освободилась!

              Ответ краткий - никак. Серьезно.
              Подробнее - грузить ее в отдельный AppDomain и делать ему Unload. Тогда выгрузятся все сборки в него загруженные
                Так, тогда придется делать некий менеджер, который будет постоянно прибавлять порядковый номер файла (библиотеки) при сборке и в следующий раз загружить именно его! Криво. Но что делать? Раз так задача стоит. :)
                  Цитата DarkKo, 15.09.03, 13:14:08
                  Так, тогда придется делать некий менеджер, который будет постоянно прибавлять порядковый номер файла (библиотеки) при сборке и в следующий раз загружить именно его! Криво. Но что делать? Раз так задача стоит. :)

                  Зачем??? Сборка уже в метаданных содержит номер версии. А домен придется перегружать при изменении версии, вот и весь менеджер
                  Assembly.GetName().Version
                  Сообщение отредактировано: kl -
                    Хорошая мысль с доменом! Это гениально.

                    А почему у меня вот так сразу не загружается библиотека в домен?
                    (на третьей строчке ошибка)
                    ExpandedWrap disabled
                      <br>AppDomain Domen = AppDomain.CreateDomain("Domen Addition Dll");<br>Assembly SecondScriptAssembly;<br>SecondScriptAssembly = Domen.Load(filename);<br>
                      Цитата DarkKo, 15.09.03, 14:29:53

                      AppDomain Domen = AppDomain.CreateDomain("Domen Addition Dll");
                      Assembly SecondScriptAssembly;
                      SecondScriptAssembly = Domen.Load(filename);

                      Попробуй так.
                      ExpandedWrap disabled
                        <br>// Set up the Evidence<br>Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;<br>Evidence evidence = new Evidence(baseEvidence);<br>evidence.AddAssembly("(some assembly)");<br><br>// Create the AppDomain      <br>AppDomain newDomain = AppDomain.CreateDomain("newDomain", evidence);<br>

                      Просто проблема при загрузке сборки в домен, не являющийся текущим для приложения. Смотри AppDomain.Load раздел Remarks
                      Сообщение отредактировано: kl -
                        Зачем в evidence добавлять сборку - не понимаю.
                        Пытаюсь сделать вот так:
                        ExpandedWrap disabled
                          <br>AppDomain Domen = AppDomain.CreateDomain("NewDomain");<br>try<br>{<br>Object fromdll = Domen.CreateInstanceFromAndUnwrap(filename, "dinamo.PrintMessage");<br>}<br>

                        И при этом ловлю exception:
                        SerializationException
                        Который мне говорит, что мойе сборки (перечисляет ее имя) найти не может.
                          кстати при создании домена передай еще сетап с ShadowCopyFiles = true - тогда сможешь сборку на новую заменить
                          Я не помню, там были какие-то траблы с этим, но сейчас проверить не могу... надо поэкспериментировать, например загрузить сборку из Гака или передать strong name. Насчет strong name особенно актуально если у тебя фреймворк 1.1
                          Сообщение отредактировано: kl -
                            Знаешь что я подумал! Я полумал, что текущий домен можно сделать с ShadowCopyFiles = true. Посмотрим, получится или нет.
                            Framework у меня действительно 1.1
                            А с GAC я не пробовал. Чем это поможет?
                              Когда на текущий домен ставишь SetShadowCopyFiles(), то пересборка dll возможна. Т.к. библиотека была куда-то скопирована и от туда юзается. Но при следующем вызове LoadFrom уже не получается достать новую библиотеку. Как он себе копию сделал, так ее и использует.
                              А в новый домен так и не получается сборку засосать.
                                Да ты прав, я наверное глупость сказал вчера, совсем забыл, что при загрузке сборки в нетекущий домен - она автоматом загрузится и в текущий. Иначе невозможен обмен данными. Извиняй - давно это уже было
                                Если у тебя 1.1, то скорее всего он от тебя хочет strong name сборки. ГАК я посоветовал чисто для эксперимента, типа найдет/не найдет
                                И последнее: учти что при загрузке сборки в отдельный домен все взаимодействие пойдет через ремоутинг, со всеми вытекающими:
                                1) Передаваемые в качестве параметров и возвращаемого значения типы должны быть сериализуемыми.
                                2) Сборка должна быть загружена и в вызывающем домене и в выполняющем
                                3) Если объект передается по значению, то при попытке доступа к нему тебе отдадут копию.
                                4) Статик-переменные в разных доменах разные
                                5) Если объект передается по ссылке то доступ к нему происходит через прокси, что сказывается на скорости вызова не в лучшую сторону

                                А подгрузить новую он и не даст, т.к. это равнозначно выгрузке старой! Кто будет проверять совместимость типов например? Представь что у тебя у клиента остались ссылки на типы из старой сборки, а тут ты раз и меняешь ее на новую. в .NET такое никогда не позволяется, код должен быть безопасен. Наверное среда могла быть проверять и кидать что-нить типа TypeUnloadException но тогда извини - теряем в производительности. В общем хочешь пересобирать на лету - экспериментируй с отдельным доменом
                                Сообщение отредактировано: kl -
                                  Смотри на пример в доке AppDomain.Load, конкретнее на MyResolver. Если у тебя его нет - скажи я скопирую сюда. Там упоминается, что нужен стронг нэйм, а так как его нет, сборка грузится как байтовый массив. Пробуй
                                    Я всех порвал!
                                    Блин, получилось! :)
                                    Во как надо!
                                    ExpandedWrap disabled
                                      <br>AppDomainSetup appDomainSetup = new AppDomainSetup ();<br>appDomainSetup.ShadowCopyFiles = "true";<br>AppDomain Domen = AppDomain.CreateDomain ("AppDomainFriendlyName", AppDomain.CurrentDomain.Evidence, appDomainSetup);<br>Domen.SetShadowCopyFiles();<br>Object fromdll = Domen.CreateInstanceFromAndUnwrap(dirrectory + name, "PrintMessage");<br>Console.Write(fromdll.ToString()+"\n");<br>Console.Write(fromdll.GetType().ToString()+"\n");<br>MethodInfo Method = fromdll.GetType().GetMethod("Message");<br>Method.Invoke(fromdll,null);<br>AppDomain.Unload(Domen);<br>

                                    Удивительно только что приходится повторный раз вызывать Domen.SetShadowCopyFiles(); , ведь в setup я уже прописал, appDomainSetup.ShadowCopyFiles = "true";.

                                    При этом сама библиотека вот так написана.
                                    ExpandedWrap disabled
                                      <br>using System;<br>using System.Runtime.InteropServices;<br>public class PrintMessage: MarshalByRefObject<br>{<br> public void Message()<br> {<br>          Console.Write("Inside dll module ONE MORE TIME\n");<br> }<br>};<br>

                                    Тоже самое но с namecpase (ну в библиотечном файле) реализовать не получилось.
                                      2kl
                                      Кстати, когда я пробовал чеоез AppDomain.Load - он мне конкретно отказывался находить файл. :)
                                      Сейчас посмтрю то что ты посоветовал.
                                      Сообщение отредактировано: DarkKo -
                                        Кстати, вот как релизован там MyResolver - это просто создается тип и грузится в dll?
                                        Я так понимаю, что это нужно, для того что бы переопределять содержимое dll в ран-тайм. Но не перезагружать.
                                          Цитата DarkKo, 16.09.03, 11:00:06
                                          Кстати, вот как релизован там MyResolver - это просто создается тип и грузится в dll?
                                          Я так понимаю, что это нужно, для того что бы переопределять содержимое dll в ран-тайм. Но не перезагружать.

                                          loadfile сборку находит а AppDomain.Load нет. Вот они перехватывают событие разрешения имени сборки и грузят ее как массив байт
                                            Кстати, про быстроту загрузки.
                                            Если не выгружать сборку (в смысле домен), а просто загружать ее и загружать. Как можно убыстрить подкачку dll. Вот первый раз (в отладчике) оа у меня загружается аж 1 секунду. А последующие разы - аж до 1мс. Хотелось бы первый раз порядка миллисекунд, а последующие раз в 10 быстрей.

                                            2kl
                                            Ты говорил про проверку версии.
                                            Цитата
                                            Assembly.GetName().Version

                                            Как мне найти эту самую Assembly, что бы сравнить со сборкой, которую я загружаю, и как узнать версию сборки, которую я загружаю не загрузив ее?
                                              Цитата DarkKo, 16.09.03, 12:32:11
                                              Ты говорил про проверку версии.
                                              Как мне найти эту самую Assembly, что бы сравнить со сборкой, которую я загружаю, и как узнать версию сборки, которую я загружаю не загрузив ее?

                                              Ну как, либо AppDomain.CurrentDomain.GetAssemblies, перебираешь их и находишь свою по имени, либо через статик метод Assembly.GetAssembly куда передаешь тип своего объекта (который живет в этой сборке)
                                                При передачи ссылки на обхект из одного домен а в другой возникают жуткие проблемы. Хотя казалось, что код работает, но другой такойже код - уже не работает.
                                                Я вычитал:
                                                Цитата

                                                Однако ручная сериализация – это дополнительный код, а значит, и дополнительное время, ну и разумеется, дополнительные ошибки, а стало быть, снова время и нервы. Если учесть, что стандартная сериализация в .NET обеспечивает автоматическую сериализацию графов объектов (обеспечивая его восстановление при десериализации, с восстановлением всех связей), то становится понятным, что к ручной сериализации стоит прибегать, только имея серьезные основания. Если же сериализуемый объект содержит ссылки на MarshalByRefObject (передаваемые по ссылке объекты), то сериализация существенно усложняется, так как придется залезть в довольно низкоуровневые вещи, чтобы обеспечить передачу ссылки на объект в другой процесс (домен приложения, контекст).

                                                http://www.rsdn.ru/article/dotnet/DotNetSerial.xml

                                                У меня как раз такой вот объект MarshalByRefObject, и как раз вылезают (при Invoke метода) эксепшены на счет сериализации.
                                                Подскажите, где мне мозгов не хватает, что бы мне сдалать стабильный, полностью понятный код.
                                                  Ты внимательно читал мой пост №14?
                                                  1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                  0 пользователей:


                                                  Рейтинг@Mail.ru
                                                  [ Script execution time: 0,0472 ]   [ 15 queries used ]   [ Generated: 18.07.25, 01:14 GMT ]