Использование MarshalByRefObject без необходимости загружать сборки, загруженные во второй AppDomain
У меня есть 2 домена приложений
1: host
2: plugin
Теперь у меня есть PluginLoader
который наследует MarshalByRefObject
потому что я хочу вернуть количество плагинов, загруженных в этот домен. Я использую его для загрузки плагинов в плагин-AppDomain с помощью domain.DoCallBack(new CrossAppDomainDelegate(loader.LoadPlugin));
В плагине AppDomain я загружаю плагин, который ссылается на EntityFramework. Теперь мой host-AppDomain хочет загрузить EntityFramework.dll
тоже, когда я загружаю плагин в plugin-AppDomain, который использует EntityFramework.dll
, Это происходит только тогда, когда мой PluginLoader
продолжается MarshalByRefObject
, Когда PluginLoader
не расширяет MarshalByRefObject (т.е. он сериализуется для выполнения вызова), хост-домен приложения не хочет загружаться EntityFramework.dll
,
Поэтому мой вопрос: возможно ли сделать вызов в другой домен приложений, используя MarshalByRefObject, без необходимости загружать все сборки, запрошенные другим доменом приложений? Или, в более общем плане: как сделать вызов в AppDomain и вернуть значение, не загружая сборки, запрошенные другим AppDomain?
Вот мой код для справки:
static void Main(string[] args)
{
var pluginPath = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath) + "\\Plugins";
var files = Directory.GetFiles(pluginPath, "*.dll")
.Where(f => f.EndsWith("ArtNet.dll")); // just want to test this one plugin atm
Console.WriteLine("Found {0} files", files.Count());
foreach (var file in files)
{
Console.WriteLine("Loading {0}", file);
Console.WriteLine("Creating AppDomain");
var setup = new AppDomainSetup();
setup.PrivateBinPath = pluginPath;
var domain = AppDomain.CreateDomain(file, null, setup);
var loader = new PluginLoader { File = file, HubUri = hubUri };
domain.DoCallBack(new CrossAppDomainDelegate(loader.LoadPlugin));
if (loader.NumberOfLoadedPlugins > 0)
{
Console.WriteLine("Loaded {0} plugins from {1}", loader.NumberOfLoadedPlugins, file);
appDomains.Add(file, domain);
}
else
{
Console.WriteLine("{0} did not contain any plugins, unloading AppDomain", file);
AppDomain.Unload(domain);
Console.WriteLine("Appdomain Unloaded for file {0}", file);
}
}
Console.ReadKey();
}
И прокси
[Serializable]
public class PluginLoader : MarshalByRefObject
{
public string File { get; set; }
public string HubUri { get; set; }
public int NumberOfLoadedPlugins { get; set; }
public void LoadPlugin()
{
var plugins = new List<IPlugin>();
Console.WriteLine("Loading Assembly");
var pluginAssembly = Assembly.LoadFile(File);
Console.WriteLine("Assembly loaded");
var pluginTypes = pluginAssembly.ExportedTypes.Where(t => t.GetInterfaces().Any(i => i.Equals(typeof(IPlugin))));
Console.WriteLine("Found {0} types implementing IPlugin", pluginTypes.Count());
foreach (var pluginType in pluginTypes)
{
try
{
Console.WriteLine("Looking for a parameterless Constructor in {0}", pluginType.Name);
var constructor = pluginType.GetConstructor(Type.EmptyTypes);
if (constructor != null)
{
Console.WriteLine("Found a parameterless constructor");
var plugin = (IPlugin)constructor.Invoke(null);
plugins.Add(plugin);
Console.WriteLine("Plugin of type {0} created", pluginType.Name);
plugin.StartAsync(HubUri).Wait();
Console.WriteLine("{0}.StartAsync({1}) called", pluginType.Name, HubUri);
}
else
Console.WriteLine("No Constructor found");
}
catch (Exception e)
{
Console.WriteLine("Exception occured");
Console.WriteLine(e);
}
}
PluginRegister.Plugins.AddRange(plugins);
NumberOfLoadedPlugins = plugins.Count;
}
}