Вопрос: Передача данных через appdomains с помощью MarshalByRefObject


У меня есть небольшая проблема с передачей некоторых данных между двумя .NET-доменами, и я надеюсь, что кто-то здесь может мне помочь.

В основном то, что у меня есть, является основным приложением ( Главный ), который загружает сборку  а также В  в его основной домен, тогда, когда я запускаю плагин ( С ) Главный  вызывает метод создания домена В  который создает новый домен и нагрузки С  и экземпляр В  в него, так что С  может получить доступ только В  а не другие.

В  содержит указатель на IDispatch Главный  но только он, кажется, получает его после того, как он загружается в новый домен с помощью С , То, что я пытаюсь сделать, это отправить копию указателя из нового экземпляра домена В  и отправить его на  который по-прежнему работает в домене по умолчанию.

Только для записи, которую я контролирую A, B и C  но нет Главный

Извините, если это немного сложно понять, я старался объяснить это.

Код:

В:

public class Tunnel : MarshalByRefObject
{
    public void SetPointer(int dispID)
    {
        IntPtr pointer = new IntPtr(dispID);
    }
}

В B:

//Call by Main after loading plug in but after A.dll is loaded.
public void CreateDomain()
{
  AppDomain maindomain= AppDomain.CurrentDomain;
  tunnel = (Tunnel)maindomain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
                                                      typeof(Tunnel).FullName);

   AppDomain domain = base.CreateDomain(friendlyName, securityInfo, appDomainInfo);
   //Load assembly C (plug in) in domain.
   // C uses B so it loads a new instance of B into the domain also at the same time.

  // If I do this here it creates new instance of A but I need to use the one in
  // the main domain.
  //tunnel = (Tunnel)domain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
                                                    typeof(Tunnel).FullName);
  tunnel.SetPointer(//Send data from B loaded in new domain.)

}

Поэтому в конце он выглядит примерно так:

Домен по умолчанию:

  • Main.dll
  • A.DLL
  • B.dll

Подключить домен:

  • B.dll
  • C.dll

3


источник


Ответы:


В своем коде выше вы звоните

AppDomain.CurrentDomain.CreateInstanceAndUnwrap(...)

Это просто круглый способ создания объекта в текущем домене, так же, как если бы вы только что вызвали конструктор. Вы должны вызвать этот метод в удаленном домене, т.е.

AppDomain domain = AppDomain.Create(...)
Tunnel tunnel = (Tunnel)domain.CreateInstanceAndUnwrap(...)

Если вы затем вызовете tunnel.SetPointer (...), который будет запущен на удаленном объекте.


8



Поэтому я предполагаю, что:

class B : MarshallByRef

с тем, что вам нужно только создать объект в домене из класса A:

AppDomain domain = ...
B inst = (B) domain.CreateInstanceAndUnwrap(typeof(B).Assembly.FullName, typeof(B).FullName);
inst.DoPlugin("C");

Метод DoPlugin () будет динамически загружать тип «C» и вызывать любые методы.


0



Возможно, вам придется копировать пути поиска и доказательства при создании дочерних доменов (особенно для работы в библиотеках единичных тестов):

var dom = AppDomain.CreateDomain("NewDomain",
    AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.BaseDirectory,
    AppDomain.CurrentDomain.RelativeSearchPath, false);
try
{
    var tunnel = (MyMarshallByRef)dom.CreateInstanceAndUnwrap(
        typeof(MyMarshallByRef).Assembly.FullName,
        typeof(MyMarshallByRef).FullName);

    tunnel.DoStuff("data");
}
finally
{
    AppDomain.Unload(dom);
}

Также обратите внимание, что любые аргументы DoStuff метод и любые возвращаемые им типы должен  быть отмеченным [Serializable]


0