Я делаю менеджер плагинов, который взаимодействует со сторонним кодом. Я хотел бы, чтобы плагины перезагружались во время выполнения, а также получали доступ к стороннему коду (в домене приложений по умолчанию) из плагинов.
Я пытался использовать AppDomains, но я не нашел способа вызвать любой метод без необходимости оборачивать каждый доступный метод / объект.
Я рассмотрел пару вопросов, и, например, этот ответ , ссылки в нем и этот ответ дали некоторое представление о том, как работает связь между доменами AppDomain.
Я успешно создал прокси-класс для одного метода, который будет вызываться в домене приложений по умолчанию благодаря второму ответу, но для этого потребуется добавить один для каждого возможного вызова метода, который будет вызываться из плагина.
Я также пытался использовать код с Action в качестве переданного типа, чтобы позволить плагину передавать некоторый код для выполнения в AppDomain по умолчанию, но это не удалось с различными ошибками. Вот моя последняя попытка.
Основное применение:
[Serializable]
public sealed class DelegateWrapper<T1>
{
private Action<T1> _someDelegate;
public Action<T1> SomeDelegate
{
get
{
return _someDelegate;
}
set
{
if (value == null)
_someDelegate = null;
else
_someDelegate = new myDelegateWrapper(value).Invoke;
}
}
private sealed class myDelegateWrapper : MarshalByRefObject
{
public void Invoke(T1 input)
{
_delegate(input);
}
private Action<T1> _delegate;
public myDelegateWrapper(Action<T1> dlgt)
{
_delegate = dlgt;
}
}
}
[Serializable]
public sealed class P
{
public Action Action { get; }
public P(Action action)
{
this.Action = action;
}
}
private static readonly DelegateWrapper<P> PerformWrapper=new DelegateWrapper<P>();
public static void Init()
{
PerformWrapper.SomeDelegate = p => p.Action();
}
Внутри нового AppDomain метод Perform вызывает execute.SomeDelegate.
Плагин (также выполняется в новом домене приложений):
Perform(new P(() =>
{
//Third-party code
}));
Это приводит к исключению, говорящему о том, что он не может найти сборку плагина, которую я загрузил вручную в домене плагина. Я предполагаю, что он пытается загрузить его в домене по умолчанию. Есть ли способ обойти это?
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Plugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies
Полная трассировка стека здесь: https://pastebin.com/xZV7bXeV