Можно ли создать экземпляр типа "динамический" из другого 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.
Есть ли способ заставить это работать?
Ответы
Ответ 1
Как показано leppie, вам необходимо реализовать IDynamicMetaObjectProvider
interface для переноса прокси-сервера, возвращаемого вам, а затем вы можете использовать вызовы make dynamic
.
В вашей реализации вы хотите взять завернутый прокси-сервер и перенаправить все вызовы на статический ExecuteMessage
method на вкладке RemotingServices
class, который займет ваш прокси, а также IMethodCallMessage
.
Обратите внимание, что реализация интерфейса IMethodCallMessage
не является тривиальной. Кроме того, вам необходимо правильно интерпретировать реализацию IMethodReturnMessage
, чтобы получить правильное возвращаемое значение, ref
и out
. (если есть).
Тем не менее, как правило, лучше представить сборку, которая содержит только интерфейс для клиента и сервера; если какой-либо метод каким-либо образом изменяется на стороне сервера, даже если клиентская сторона использует dynamic
, вам все равно придется изменить сайт вызова для внесения изменений. По крайней мере, с интерфейсом вы получаете некоторый тип проверки времени компиляции, который всегда предпочитает ошибку времени выполнения.