2015-06-15 2 views
0

У меня есть сценарий, в котором я хотел бы достичь простой связи между родителем AppDomain и его детьми. То, что я пытаюсь сделать, похоже, что это сработает, но я столкнулся с проблемой, приведенный ниже фрагмент является примером.Как передать строго типизированный объект MarshalByRefObject через границу AppDomain?

Результаты программы в сообщении Нет конструктор нашел для C ::. Т е р (System.MarshalByRefObject) так это выглядит, как среда выполнения отклонило конструктор, принимающий параметр типа, который я передаю в к CreateInstanceFromAndUnwrap call. Я могу понять, почему работает экземпляр B, и я ожидал, что C будет вести себя одинаково, так почему же это не так?

Спасибо!

EDIT: Я сделал небольшое обновление примера кода ниже, после того как Ганс указал на ошибку пешехода в моем первом примере. Поэтому, пока у нас еще есть вымышленное свойство ApplicationBase на наших дочерних доменах приложений, мы можем видеть, что загружается правильная сборка, и мы можем вызвать конструктор, который мы пытаемся вызвать.

Замечание Ганса делает, чтобы сделать код, но я не думаю, что я могу установить ApplicationBase в реальной вещи, чтобы быть базой родительского домена.

Выход на второй итерации цикла теперь следующим образом:
C
Первоначально Загруженный: mscorlib
После Unwrap: mscorlib
После Unwrap: Foo
Пустота .ctor (A)
Конструктор по типу 'C' не найден.

using System; 
using System.Linq; 
using System.Reflection; 

class A : MarshalByRefObject { } 

class B : MarshalByRefObject 
{ 
    public B(MarshalByRefObject obj) { } 
} 

class C : MarshalByRefObject 
{ 
    public C(A obj) { } 
} 

static class Program 
{ 
    static void Main(string [] args) 
    { 
     foreach (var type in new [] { typeof(B), typeof(C) }) 
     { 
      try 
      { 
       Console.WriteLine(type.FullName); 

       var setup = CreateSetup(); 

       var domain = AppDomain.CreateDomain("foo", AppDomain.CurrentDomain.Evidence, setup); 

       foreach (var ass in domain.GetAssemblies()) 
       { 
        Console.WriteLine("Initially Loaded: {0}", ass.GetName().Name); 
       } 

       domain.CreateInstanceFromAndUnwrap(typeof(A).Assembly.Location, typeof(A).FullName); 

       foreach (var ass in domain.GetAssemblies()) 
       { 
        Console.WriteLine("After Unwrap: {0}", ass.GetName().Name); 
       } 

       var constructors = domain.GetAssemblies() 
        .ToList() 
        .SelectMany(ass => ass.DefinedTypes) 
        .First(t => t.Name == "C") 
        .GetConstructors(); 

       foreach (var constructor in constructors) 
       { 
        Console.WriteLine(constructor); 
       } 

       CreateWrapped(domain, type); 

       AppDomain.Unload(domain); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
      } 
     } 
    } 

    static AppDomainSetup CreateSetup() 
    { 
     return new AppDomainSetup 
     { 
      ApplicationBase = "foo", 
      ApplicationName = "bar", 
      DisallowBindingRedirects = false, 
      ConfigurationFile = "baz", 
      LoaderOptimization = LoaderOptimization.MultiDomainHost 
     }; 
    } 

    static object CreateWrapped(AppDomain domain, Type type) 
    { 
     return domain.CreateInstanceFromAndUnwrap(
      assemblyFile: type.Assembly.Location, 
      typeName: type.FullName, 
      ignoreCase: false, 
      bindingAttr: BindingFlags.Default, 
      binder: null, 
      args: new object[] { new A() }, 
      culture: null, 
      activationAttributes: null 
     ); 
    } 
} 
+1

AppDomainSetup.ApplicationBase - проблема. Разрешение типа A - проблема с курицей и яйцом, она не может найти сборку, содержащую A. –

+0

О, боже, как я пропустил это, когда писал это. Моя настоящая проблема не должна быть зафиксирована в этом Минимальном нерабочем примере. – arfbtwn

+0

@ HansPassant, я обновил образец, не могли бы вы взглянуть еще раз? – arfbtwn

ответ

0

Как отметил Ханс проблема была в моей CreateSetup функции в ApplicationBase который я исправленный здесь:

static AppDomainSetup CreateSetup() 
{ 
    return new AppDomainSetup 
    { 
     ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, 
     ApplicationName = "bar", 
     DisallowBindingRedirects = false, 
     ConfigurationFile = "baz", 
     LoaderOptimization = LoaderOptimization.MultiDomainHost 
    }; 
} 

С этой модификацией примером программа корректно выполняет как с B и C реализованными в их дочерние домены.

После принудительной сборки загрузка, которую я выполнял, не требуется после того, как я все еще не могу объяснить, почему дочерний домен приложения не может разрешить конструктор C после первого создания объекта A для загрузки необходимой сборки.

Моя лучшая попытка объяснения заключается в том, что использование по умолчанию load context с доменом приложения, имеющим недопустимый путь, указанный для его базы, вызывает сбой разрешения во время зондирования для C.

Смежные вопросы