If you transfer an object from another domain, you thereby load it into your domain, which you just want to avoid. The solution may be to pass primitive types. In order not to limit yourself to simple callbacks, you need to use MarshalByRefObject
(they are not copied between domains, but are executed in the domain where they are created).
So, here is the working code.
This is the DomainsPlugin.dll plugin:
namespace DomainsPlugin { public class Plugin { public IEnumerable<AssemblyName> GetNames() { return AppDomain.CurrentDomain.GetAssemblies().Select(asm => asm.GetName()); } } }
Nothing special, just a working method.
Now the main program:
namespace DomainsMain { class Program { static void Main(string[] args) { // в этом каталоге бежит программа var executableDir = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location); // это каталог, где лежит плагин. // у вас он будет лежать, понятно, в другом месте var pluginDir = Path.GetFullPath(Path.Combine( executableDir, "..", "..", "..", "DomainsPlugin", "bin", "Debug")); // оригинал плагина var pluginSourceFile = Path.Combine(pluginDir, "DomainsPlugin.dll"); // а сюда мы его скопируем, и отсюда будем загружать var pluginWorkingFile = Path.Combine(executableDir, "DomainsPlugin.dll"); // копируем File.Copy(pluginSourceFile, pluginWorkingFile, overwrite: true); // окей, теперь новый домен var pluginDomain = AppDomain.CreateDomain("Plugin"); // теперь, создаём экземпляр нашего класса в новом домене // у нас на него реально лишь прокси-объект var resident = (Resident)pluginDomain.CreateInstanceAndUnwrap( Assembly.GetExecutingAssembly().FullName, "DomainsMain.Resident"); // получили данные resident.Obtain(); // выводим их foreach (var r in resident.Result) Console.WriteLine(r.ToString()); // выгружаем домен... AppDomain.Unload(pluginDomain); // ... и удаляем плагин File.Delete(pluginWorkingFile); } } // простой класс, будет выполняться в другом домене public class Resident : MarshalByRefObject { public List<AssemblyName> Result; public void Obtain() { // загружаем библиотеку var asm = Assembly.LoadFrom("DomainsPlugin.dll"); var type = asm.GetType("DomainsPlugin.Plugin"); // и вызываем функцию из неё через рефлексию // можно было бы закастить к интерфейсу, если объявить его в // этой или другой общей dll-ке var p = Activator.CreateInstance(type); var method = type.GetMethod( "GetNames", BindingFlags.Instance | BindingFlags.Public); var result = (IEnumerable<AssemblyName>)method.Invoke(p, null); // сохраняем результат. это поле будет доступно из первоначального домена Result = result.ToList(); } } }
On my machine, from under Visual Studio, it produces:
mscorlib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089
Microsoft.VisualStudio.HostingProcess.Utilities, Version = 14.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a
DomainsMain, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
System.Core, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089
DomainsPlugin, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null
Update: the resident function ( Obtain()
) may well return a value. But this value must be serialized in order to “squeeze” between domains.
For our example, correct the Resident
class:
public class Resident : MarshalByRefObject { public List<AssemblyName> Obtain() // <-- поменяли возвращаемый тип { // и убрали свойство Result // загружаем библиотеку var asm = Assembly.LoadFrom("DomainsPlugin.dll"); var type = asm.GetType("DomainsPlugin.Plugin"); // и вызываем функцию из неё через рефлексию // можно было бы закастить к интерфейсу, если объявить его в // этой или другой общей dll-ке var p = Activator.CreateInstance(type); var method = type.GetMethod( "GetNames", BindingFlags.Instance | BindingFlags.Public); var result = (IEnumerable<AssemblyName>)method.Invoke(p, null); return result.ToList(); } }
Now the call from the main code looks like this:
// получили данные var result = resident.Obtain(); // выводим их foreach (var r in result) Console.WriteLine(r.ToString());
Assembly
class representing the loaded assembly to the main domain, you are actually loading your assembly and into it. - PetSerAl