2016-07-21 3 views
1

Я пытаюсь создать систему с возможностью «горячей» замены, где пользователь может динамически загружать и выгружать DLL. Необходимо, чтобы основное приложение перезапустилось как можно меньше, поэтому я перемещаю как можно больше функциональности для внешних библиотек. Из каких исследований я выяснил, мне нужно создать второй AppDomain и загрузить DLL в это, а затем просто передать параметры и т. Д., Чтобы запустить его. В настоящее время, я считаю, что у меня большая часть работы с программой, но я сталкиваюсь с ошибкой при вызове функции AppDomain.Unwrap() объекта из CreateInstance. Ошибка заключается в следующем:C# AppDomain не может загрузить DLL

System.InvalidCastException: Unable to cast transparent proxy to type 'Program1.Loader'. 

Вот код загрузки:

try { 
    unload(dom,out loader,true); 
    dom=null; 
    AppDomainSetup dms = new AppDomainSetup(); 
    dms.ConfigurationFile=Environment.CurrentDirectory+Path.DirectorySeparatorChar+"Program1.exe.config"; 
    dms.ApplicationBase=Environment.CurrentDirectory+Path.DirectorySeparatorChar+"Plugins"; 
    Evidence ev = AppDomain.CurrentDomain.Evidence; 
    dom=AppDomain.CreateDomain("PluginManager",ev,dms); 
    AssemblyName an = AssemblyName.GetAssemblyName(Environment.CurrentDirectory+"\\Plugins\\PluginManager.dll"); 

    ObjectHandle obj = dom.CreateInstance(an.FullName,"PluginManager.PluginManager"); 
    loader = (Loader)obj.Unwrap(); 
    loader.LoadAssembly(@"PluginManager.dll"); 

    if(!suppressOutput) 
     Console.WriteLine("Reload successful."); 
    } 
    catch(Exception e) { 
    unload(dom,out loader,true); 
    loader=null; 
    Console.WriteLine("PluginManager failed loading. Enter \"reload\" to try again.\n"); 
    Console.Write(e+"\n\n"); 
    } 

Эта линия, где выбрасывается ошибка:

loader = (Loader)obj.Unwrap(); 

внешней DLL практически не имеет код это, поскольку это является доказательством концепции. Он выглядит следующим образом:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace PluginManager { 
    public class PluginManager:MarshalByRefObject { 
    public void run(string comm) { 
     Console.WriteLine(comm); 
    } 
    } 
} 

Редактировать: Вот код для класса загрузчика.

class Loader:MarshalByRefObject { 
    private Assembly _assembly; 

    public override object InitializeLifetimeService() { 
     return null; 
    } 

    public void LoadAssembly(string path) { 
     _assembly=Assembly.Load(AssemblyName.GetAssemblyName(path)); 
    } 

    public object ExecuteStaticMethod(string typeName,string methodName,params object[] parameters) { 
     Type type = _assembly.GetType(typeName); 
     MethodInfo method = type.GetMethod(methodName,BindingFlags.Static|BindingFlags.Public); 
     return method.Invoke(null,parameters); 
    } 
    } 

ответ

0

Похоже, вы пытаетесь создать объект типа PluginManager в AppDomain, а затем бросили его прокси типа Loader (который отсутствует в вашем примере кода).

Проблема заключается в этих строках:

ObjectHandle obj = dom.CreateInstance(an.FullName,"PluginManager.PluginManager"); 
loader = (Loader)obj.Unwrap(); 

Это будет работать, если вы либо создать экземпляр Loader вместо PluginManager - или - приведение к PluginManager вместо Loader. Моя догадка бывший:

ObjectHandle obj = dom.CreateInstance(an.FullName,"LoaderNamespace.Loader"); 

(Заменить LoaderNamespace с реальным.)

+0

Я обновил код, чтобы включить загрузчик актеров. Не могли бы вы объяснить свой ответ с помощью небольшого кода? Я не уверен, что вы хотите, чтобы я сделал. – Bioniclegenius

+0

Спасибо за редактирование! Но Loader находится в основной программе. Не сработает ли CreateInstance при попытке загрузить его из DLL? – Bioniclegenius

+0

Но вы не пытаетесь загрузить Loader, вы пытаетесь загрузить PluginManager. Это проблема. Это то, что вы переходите в AppDomain.CreateInstance. –

Смежные вопросы