C#后绑定在运行时卸载DLL

时间:2016-04-29 08:54:45

标签: c# .net

我想在运行时将.dll加载到我自己的c#程序中作为插件。如果有新的更新卸载现有的插件dll( InvokeHelper。 dll )并下载更新的.dll InvokeHelper.dll )并将其加载到程序中而不会终止该过程。(我的应用程序)。我阅读了这些文章来完成这些任务(MSDN, Article2)但是这段代码仍无法动态卸载.dll

当我通过进程资源管理器查看附加的dll时,附加的dll没有被卸载。它存在于process explorer dll列表中。我认为如果dll卸载成功我想手动重命名旧的dll并替换新的。

InvokeHelper.dll 来源:

using System;

namespace InvokeHelper
{
    public class LateBindingInvokeHelper
    {
        public void PrintHello()
        {
            using (System.IO.StreamWriter w = new System.IO.StreamWriter(@"Invoker.txt", true))
            {
                w.WriteLine(DateTime.Now.ToString());
                w.Flush();
            }
        }
    }
}

加载Dll功能:

 private AppDomain domain = null;
 private void LoadDll()
        {
            AppDomainSetup domInfo = new AppDomainSetup();
            domInfo.ApplicationBase = System.Environment.CurrentDirectory;
            Evidence adevidence = AppDomain.CurrentDomain.Evidence;
            domInfo.DisallowBindingRedirects = false;
            domInfo.DisallowCodeDownload = true;
            domain = AppDomain.CreateDomain("MyDomain", adevidence , domInfo);

            Type type = typeof(Proxy);
            var value = (Proxy)domain.CreateInstanceAndUnwrap(
                type.Assembly.FullName,
                type.FullName);

            var assembly = value.GetAssembly(@"C:\dev\ExBinder\ExBinder\bin\Debug\InvokeHelper.dll");
            Type[] mytypes = assembly.GetTypes();
            BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
            foreach (Type t in mytypes)
            {
                MethodInfo[] mi = t.GetMethods(flags); // you can change this flag , commented some flags :) view only plublic or bla bla 
                Object obj = Activator.CreateInstance(t);
                foreach (MethodInfo m in mi)
                {
                    if (m.Name.Equals("PrintHello")) m.Invoke(obj, null); //my func name :) you can set this via config :D
                }
            }
        }

    private void button2_Click(object sender, EventArgs e)
    {
        LoadDll();
        AppDomain.Unload(domain);
    }

代理类

public class Proxy : MarshalByRefObject
    {
        public Assembly GetAssembly(string assemblyPath)
        {
            try
            {
                return Assembly.LoadFile(assemblyPath);
            }
            catch (Exception)
            {
                return null;               
            }
        }
    }

enter image description here

1 个答案:

答案 0 :(得分:2)

问题是您在单独的AppDomain中加载程序集并通过代理返回Assembly,因此同样的程序集也会加载到您的默认AppDomain中。 我已将您的调用逻辑移到代理类中并且它已经工作了。

public class Proxy : MarshalByRefObject
{
    public void Run()
    {
        var assembly = AppDomain.CurrentDomain.Load(File.ReadAllBytes(@"C:\Users\Mkrtich_Mazmanyan\Downloads\ExBinder\Exbinder\bin\Debug\InvokeHelper.dll"));

        Type[] mytypes = assembly.GetTypes();
        BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
        foreach (Type t in mytypes)
        {
            MethodInfo[] mi = t.GetMethods(flags); // you can change this flag , commented some flags :) view only plublic or bla bla elshan
            Object obj = Activator.CreateInstance(t);
            foreach (MethodInfo m in mi)
            {
                if (m.Name.Equals("PrintHello")) m.Invoke(obj, null); //my func name :) you can set this via config :D
            }
        }
    }
}

调用部分将是:

value.Run();