Подтвердить что ты не робот

Можно ли создать экземпляр типа "динамический" из другого AppDomain?

Я пытаюсь загрузить тип из другой сборки (неизвестной во время сборки) в качестве "dynamic" и выполнить метод для этого типа. Моя цель - полностью отключить "плагин" от родительского приложения, так что нет требования для какого-либо общего кода или общего типа интерфейса. Интерфейс подразумевается с помощью ожидаемой сигнатуры метода на загруженном типе.

Это работает:

dynamic myObj = Assembly.Load("MyAssembly").CreateInstance("MyType");
myObj.Execute();

Однако это будет загружать этот тип в текущий AppDomain вместе со всеми его зависимыми сборками. Я хочу изменить это, чтобы позволить мне делать то же самое в отдельном AppDomain.

Это работает, но не использует динамическое ключевое слово, мне нужно знать явный тип, который я создаю, чтобы вызвать метод Execute:

var appDomain = AppDomain.CreateDomain(domainName, evidence, setup);
var myObj = appDomain.CreateInstanceAndUnwrap(assembly, type);
typeof(IMyInterface).InvokeMember("Execute",  BindingFlags.InvokeMethod, null, myObj);

Это по существу мой целевой случай, и я пытался заставить что-то вроде этого работать:

dynamic myObj = ad.CreateInstanceAndUnwrap(assembly, type);
myObj.Execute();

Я продолжаю заканчивать RuntimeBinderException с сообщением "System.MarshalByRefObject" не содержит определения для "Execute" ". Это сообщение имеет смысл, конечно, оно не содержит определения для "Execute", но я знаю, что тип, который я создаю, действительно содержит метод "Execute". Я предполагаю, что здесь что-то происходит с прозрачным прокси-сервером, который мешает этому работать, но я не уверен, что.

Мой фактический класс, который я пытаюсь создать, выглядит следующим образом:

[Serializable]
public class MyClass : MarshalByRefObject {
  public void Execute() {
    // do something
  }
}

Я также пробовал это с помощью общего интерфейса (не моя главная цель, но я сначала пытаюсь понять это), чтобы он выглядел так:

[Serializable]
public class MyClass : MarshalByRefObject, IPlugin {
  public void Execute() {
    // do something
  }
}

Где IPlugin является известным типом в родительском приложении, и плагин имеет соответствующую ссылку во время сборки, но это тоже не работает.

Я предполагаю, что в этот момент невозможно загрузить тип как динамический по границе AppDomain.

Есть ли способ заставить это работать?

4b9b3361

Ответ 1

Как показано leppie, вам необходимо реализовать IDynamicMetaObjectProvider interface для переноса прокси-сервера, возвращаемого вам, а затем вы можете использовать вызовы make dynamic.

В вашей реализации вы хотите взять завернутый прокси-сервер и перенаправить все вызовы на статический ExecuteMessage method на вкладке RemotingServices class, который займет ваш прокси, а также IMethodCallMessage.

Обратите внимание, что реализация интерфейса IMethodCallMessage не является тривиальной. Кроме того, вам необходимо правильно интерпретировать реализацию IMethodReturnMessage, чтобы получить правильное возвращаемое значение, ref и out. (если есть).

Тем не менее, как правило, лучше представить сборку, которая содержит только интерфейс для клиента и сервера; если какой-либо метод каким-либо образом изменяется на стороне сервера, даже если клиентская сторона использует dynamic, вам все равно придется изменить сайт вызова для внесения изменений. По крайней мере, с интерфейсом вы получаете некоторый тип проверки времени компиляции, который всегда предпочитает ошибку времени выполнения.