AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 23.09.06 13:35
Оценка:
Создаю новый домер через AppDomain.CreateDomain(), но потом, при вызове CreateInstanceAndUnwrap(), для поиска сборки должно вызваться событие AssemblyResolve созданного домена, но не вызывается, в чем может быть проблема?
Код:
            AppDomain domain = AppDomain.CreateDomain("ClientDomain");
            domain.AssemblyResolve += new ResolveEventHandler(domain_AssemblyResolve);
            domain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
                                          { // сюда не заходит
                                              if(File.Exists(_deployPath + args.Name))
                                                  return Assembly.Load(_deployPath + args.Name);
                                              return null;
                                          };
            Form form = (Form)domain.CreateInstanceAndUnwrap("AssemblyName", "Type"); // тут падает

Эксепшен:
Could not load file or assembly 'AssemblyName' or one of its dependencies. 
An error relating to serialization occurred. (Exception from HRESULT: 0x8013150C)
Re: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 09:58
Оценка:
Здравствуйте, Chardex, Вы писали:

C>Создаю новый домер через AppDomain.CreateDomain(), но потом, при вызове CreateInstanceAndUnwrap(), для поиска сборки должно вызваться событие AssemblyResolve созданного домена, но не вызывается, в чем может быть проблема?


1. Подозреваю, что сборка всё же находиться, и исключение не связанно с отсутствием сборки. Вероятно исключение происходит как раз во время создания объекта (например, в конструкторе).

2. Попробуй использовать не анонимный делегат, а обычный, как в .NET 1.1

3. Кстати, тот код, которым ты в делегате загружаешь сборку, — никогда ничего не загрузит.
Re[2]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 10:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>1. Подозреваю, что сборка всё же находиться, и исключение не связанно с отсутствием сборки. Вероятно исключение происходит как раз во время создания объекта (например, в конструкторе).

Конструктор — пустой, просто форма, создання студий по умолчанию.
InnerException полученного Exception вот какой:

"Type 'System.ResolveEventArgs' in Assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable."

Может из-за этого?

А>2. Попробуй использовать не анонимный делегат, а обычный, как в .NET 1.1

Пробовал. Тоже самое

А>3. Кстати, тот код, которым ты в делегате загружаешь сборку, — никогда ничего не загрузит.

Это почему?
Re[3]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 10:46
Оценка:
StackTrace:

   at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(String assemblyName, String typeName)
   at System.AppDomain.CreateInstance(String assemblyName, String typeName)
   at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName)
   at System.AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName)
   at Weblex.Client.MainForm.CreateDomain() in ...:line 71
...

Похоже до создания объекта дело не доходит. Почему не вызвается AssemblyResolve?
Re[4]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 11:19
Оценка:
Разобрался, оказывается подписчик события AssemblyResolve должен быть в том же домене, иначе получается, что при вызове метода за пределами домена параметры метода будут сериализовываться, а ResolveEventArgs не помечени как Serializable. Я правильно рассуждаю...?
Re[5]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 11:45
Оценка:
Здравствуйте, Chardex, Вы писали:

C>Разобрался, оказывается подписчик события AssemblyResolve должен быть в том же домене, иначе получается, что при вызове метода за пределами домена параметры метода будут сериализовываться, а ResolveEventArgs не помечени как Serializable. Я правильно рассуждаю...?


Да, правильно. И как я сразу не сообразил
Re[3]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 11:51
Оценка:
Здравствуйте, Chardex, Вы писали:

А>>3. Кстати, тот код, которым ты в делегате загружаешь сборку, — никогда ничего не загрузит.

C>Это почему?

Потому что:

1. _deployPath у тебя оканчивается символом '\\' или нет? Если нет — ошибка.
2. допустим у тебя в _deployPath путь типа "C:\\Deploy Path\\", а имя сборки, которую мы ищем, — "yourasm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", тогда после твоего оператора сложения будет

_deployPath = "C:\\Deploy Path\\yourasm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

а твой файл сборки так же называется?

3. Assembly.Load(...) замени на Assembly.LoadFile(...) или Assembly.LoadFrom(...)
Re[6]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 11:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Да, правильно. И как я сразу не сообразил

Вкратце: есть главная форма, в ней создаю новый AppDomain, в нем показываю другую форму. При закрытии второй формы, выгружаю созданный домен, выгрузку делаю в методе первой формы, но почему-то после вызова AppDomain.Unload(_domain) сразу диспозится первая форма (прям сразу после вызова отладчик переходит внутрь Dispose() первой формы) и все приложение завершается.
Re[7]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 12:20
Оценка:
Здравствуйте, Chardex, Вы писали:

C>Здравствуйте, Аноним, Вы писали:


А>>Да, правильно. И как я сразу не сообразил

C>Вкратце: есть главная форма, в ней создаю новый AppDomain, в нем показываю другую форму. При закрытии второй формы, выгружаю созданный домен, выгрузку делаю в методе первой формы, но почему-то после вызова AppDomain.Unload(_domain) сразу диспозится первая форма (прям сразу после вызова отладчик переходит внутрь Dispose() первой формы) и все приложение завершается.

Хм... Это странно. А вы уверены в том, что показываете форму в другом, созданном AppDomain'е, а не в первом? Мне кажется, что в первом.
Приведите код, как создаёте домен, как сохраняете новый объект AppDomain, как показываете форму в нём и как выгружаете его.
Re[8]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 12:44
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Хм... Это странно. А вы уверены в том, что показываете форму в другом, созданном AppDomain'е, а не в первом? Мне кажется, что в первом.

А>Приведите код, как создаёте домен, как сохраняете новый объект AppDomain, как показываете форму в нём и как выгружаете его.
В главной форме:

        private void CreateDomain()
        {
            AppDomain domain = AppDomain.CreateDomain("ClientDomain");

            AssemblyResolveFinder finder = (AssemblyResolveFinder)domain.CreateInstanceAndUnwrap(typeof(AssemblyResolveFinder).Assembly.FullName, typeof(AssemblyResolveFinder).FullName);
            finder.DeployPath = _deployPath;
            domain.AssemblyResolve += new ResolveEventHandler(finder.AssemblyResolve);

            Hide();
            DomainConnector connector = new DomainConnector(_connection);
            domain.SetData(DomainConnector.ObjectName, connector);
            domain.CreateInstance("...", "...");
            connector.Terminated +=new TerminateDelegate(DomainConnectorTerminated);
        }
        private void DomainConnectorTerminated(bool close)
        {
            if (close)
                Close();
            else
                Show();
        }

        public class AssemblyResolveFinder : MarshalByRefObject
        {
            private string _deployPath;


            public Assembly AssemblyResolve(object sender, ResolveEventArgs args)
            {
                string path = _deployPath + args.Name + ".dll";
                if (File.Exists(path))
                    return Assembly.LoadFrom(path);
                return null;
            }

            public string DeployPath
            {
                get { return _deployPath; }
                set { _deployPath = value; }
            }
        }

Вторая форма:
    public partial class MainForm : Form
    {
        private DomainConnector _connector;
        bool _closing = true;
        public MainForm()
        {
            InitializeComponent();
            _connector = (DomainConnector)AppDomain.CurrentDomain.GetData(DomainConnector.ObjectName);

            button1.Click += delegate { Disconnect();};
            Closed += new EventHandler(MainForm_Closed);
            Show();
        }
        private void Disconnect()
        {
            _closing = false;
            Close();
        }

        void MainForm_Closed(object sender, EventArgs e)
        {
            Disposed += new EventHandler(MainForm_Disposed);
            _connector.Terminate(_closing);
            Dispose(true);
        }

        void MainForm_Disposed(object sender, EventArgs e)
        {
            AppDomain.Unload(AppDomain.CurrentDomain);   
        }
    }

Вспомогательный класс:

    public delegate void TerminateDelegate(bool close);
    public sealed class DomainConnector : MarshalByRefObject
    {
        public const string ObjectName = "Connector";
        public DomainConnector(IUniversalConnection connection)
        {
            _connection = connection;
        }

        IUniversalConnection _connection;
        public event TerminateDelegate Terminated;

        public IUniversalConnection Connection
        {
            get { return _connection; }
        }

        public void Terminate(bool close)
        {
            if (Terminated != null)
                Terminated(close);
        }
    }
Re[9]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 13:14
Оценка:
Так всё правильно, у тебя же в первой (главной) форме вызывается Close()! Вот она и закрывается.

1. У тебя сначала закрывается вторая форма (MainForm). И ещё до выгрузки созданного домена у тебя происходит следующее:
2. В обработчике события Closed вызывается connector.Terminate
3. В методе DomainConnector.Terminate() вызывается событие Terminated
4. На событие Terminated у тебя подписан кто? Правильно, первая форма! Обработчик называется DomainConnectorTerminated, вот он и закрывает (диспозит) первую форму.
Re[10]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 15:47
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Так всё правильно, у тебя же в первой (главной) форме вызывается Close()! Вот она и закрывается.

Если я жму на кнопочку button1, то вместо Close() вызывается Show();

А>1. У тебя сначала закрывается вторая форма (MainForm). И ещё до выгрузки созданного домена у тебя происходит следующее:

А>2. В обработчике события Closed вызывается connector.Terminate
А>3. В методе DomainConnector.Terminate() вызывается событие Terminated
А>4. На событие Terminated у тебя подписан кто? Правильно, первая форма! Обработчик называется DomainConnectorTerminated, вот он и закрывает (диспозит) первую форму.
Спасибо что объяснили как работает мой код
Re[11]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 15:59
Оценка:
Здравствуйте, Chardex, Вы писали:

А>>1. У тебя сначала закрывается вторая форма (MainForm). И ещё до выгрузки созданного домена у тебя происходит следующее:

А>>2. В обработчике события Closed вызывается connector.Terminate
А>>3. В методе DomainConnector.Terminate() вызывается событие Terminated
А>>4. На событие Terminated у тебя подписан кто? Правильно, первая форма! Обработчик называется DomainConnectorTerminated, вот он и закрывает (диспозит) первую форму.
C>Спасибо что объяснили как работает мой код

Обращайся ещё
Re[12]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 16:17
Оценка:
Здравствуйте, Аноним, Вы писали:
C>>Спасибо что объяснили как работает мой код
А>Обращайся ещё
Это же шутка была... я сам писал код и понимаю как он работает. Проблема все еще не решена
Re[13]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 16:45
Оценка:
Здравствуйте, Chardex, Вы писали:

C>Здравствуйте, Аноним, Вы писали:

C>>>Спасибо что объяснили как работает мой код
А>>Обращайся ещё
C>Это же шутка была... я сам писал код и понимаю как он работает. Проблема все еще не решена

Так а в чём проблема? Код верный. Как он работает, вы знаете. Почему вызывается Dispose() первой формы, я вам объяснил.

C>Если я жму на кнопочку button1, то вместо Close() вызывается Show();


Ну а когда вы жмёте крестик в окне второй формы (MainForm), вызывается Close().

P.S. Кстати, вы говорили, что AppDomain.Unload() вызываете из первой формы, но по коду получается, что из второй (MainForm).
Re[14]: AppDomain и AssemblyResolve
От: Chardex Россия  
Дата: 24.09.06 17:14
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Так а в чём проблема? Код верный. Как он работает, вы знаете. Почему вызывается Dispose() первой формы, я вам объяснил.

В том что когда жму на кнопочку, для первой формы делается Show а не Close, но Dispose все равно происходит.

C>>Если я жму на кнопочку button1, то вместо Close() вызывается Show();


А>Ну а когда вы жмёте крестик в окне второй формы (MainForm), вызывается Close().


А>P.S. Кстати, вы говорили, что AppDomain.Unload() вызываете из первой формы, но по коду получается, что из второй (MainForm).

Это была старая версия
Re[15]: AppDomain и AssemblyResolve
От: Аноним  
Дата: 24.09.06 19:42
Оценка:
Здравствуйте, Chardex, Вы писали:

C>Здравствуйте, Аноним, Вы писали:


А>>Так а в чём проблема? Код верный. Как он работает, вы знаете. Почему вызывается Dispose() первой формы, я вам объяснил.

C>В том что когда жму на кнопочку, для первой формы делается Show а не Close, но Dispose все равно происходит.

C>>>Если я жму на кнопочку button1, то вместо Close() вызывается Show();


А можно увидеть код кнопки?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.