在不同的 AppDomain 中加载/卸载程序集 [英] Loading/Unloading assembly in different AppDomain

查看:29
本文介绍了在不同的 AppDomain 中加载/卸载程序集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在运行时加载的程序集中执行一个方法.现在我想在方法调用后卸载那些加载的程序集.我知道我需要一个新的 AppDomain 以便我可以卸载这些库.但在这里,问题出现了.

I need to execute a method in an assembly loaded during runtime. Now I want to unload those loaded assemblies after the method call. I know that I need a new AppDomain so I can unload the libraries. But here, the problem arises.

要加载的程序集是我的插件框架中的插件.他们根本没有切入点.我所知道的是它们包含一些实现给定接口的类型.旧的非 AppDomain 代码如下所示(略有缩短):

The assemblies going to load are plugins in my plugin framework. They have no entry point at all. All I know is that they contain some types which implement a given interface. The old, non-AppDomain-code looks like this (slightly shortened):

try
{
    string path = Path.GetFullPath("C:\library.dll");
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    Assembly asm = Assembly.LoadFrom(path);
    Type[] types = asm.GetExportedTypes();
    foreach (Type t in types)
    {
        if ((t.GetInterface("IStarter") != null) && !t.IsAbstract)
        {
            object tempObj = Activator.CreateInstance(t);
            MethodInfo info = t.GetMethod("GetParameters");
            if (info != null)
            {
                return info.Invoke(tempObj, null) as string;
            }
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (args.Name.StartsWith("MyProject.View,"))
    {
        string path = Path.GetFullPath("C:\view.dll"));
        return Assembly.LoadFrom(path);
    }
    return null;
}

现在我希望它们加载到自己的 AppDomain 中:

Now I want them to load in an own AppDomain:

try
{
    string path = Path.GetFullPath("C:\library.dll");
    AppDomain domain = AppDomain.CreateDomain("TempDomain");
    domain.AssemblyResolve += CurrentDomain_AssemblyResolve;  // 1. Exception here!!
    domain.ExecuteAssembly(path);  // 2. Exception here!!
    domain.CreateInstanceFrom(...);  // 3. I have NO clue, how the type is named.
    domain.Load(...);  // 4. I have NO clue, how the assembly is named.
    domain.DoCallBack(...); // 5. Exception here!!
    // ...
}
catch (Exception ex)
{
    MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

如你所见,我已经放入了 5 个箱子.

As you can see, I have put in 5 cases.

  1. 如果我设置了事件处理程序,我会收到一个异常,提示无法找到/加载程序集(它是一个管理控制台 (mmc.exe) 管理单元.

  1. If I set the event handler, I get an exception that the assembly (it's an management console (mmc.exe) SnapIn. could not be found/loaded.

ExecuteAssembly 没有找到入口点(好吧,没有).

ExecuteAssembly does not find an entry point (well, there is none).

我不知道类型是如何命名的.如何按界面加载?

I have no clue how the type is named. How to load by interface?

类似3.如何获取程序集的名称?

Similar to 3. How to get the name of an assembly?

与 1 中的错误相同.

Same error as in 1.

我认为问题可能出在管理控制台上,或者我根本不知道我做错了什么.任何帮助表示赞赏.

I think the problem could be the managment console somehow or I have just no clue what I'm doing wrong. Any help is appreciated.

更新 1

我现在已经尝试使用发布的代理解决方案.

I have now tried using the posted proxy-solution.

AppDomain domain = AppDomain.CreateDomain("TempDomain");
InstanceProxy proxy = domain.CreateInstanceAndUnwrap(Assembly.GetAssembly(
    typeof(InstanceProxy)).FullName, typeof(InstanceProxy).ToString()) as InstanceProxy;
if (proxy != null)
{
    proxy.LoadAssembly(path);
}
AppDomain.Unload(domain);

public class InstanceProxy : MarshalByRefObject
{
    public void LoadAssembly(string path)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        Assembly asm = Assembly.LoadFrom(path);
        Type[] types = asm.GetExportedTypes();
        // ...see above...
    }
}

这也不起作用.尝试创建代理对象时,出现异常:

This does not work either. When trying to create the proxy object, I get an exception:

无法加载文件或程序集MyProject.SnapIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"或其依赖项之一.系统找不到指定的文件.
Could not load file or assembly 'MyProject.SnapIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

错误消息中的文件是加载到 mmc(管理单元)中的文件.知道如何解决这个错误吗?未调用 AppDomain.AssemblyResolve(无论是在旧域还是新域中).

The file in the error message is the on loaded into mmc (the SnapIn). Any idea how to fix this error? AppDomain.AssemblyResolve is not called (neither in the old or new domain).

更新 2

我现在已经尝试了使用 AppDomainSetup 的解决方案.现在,异常已更改为:

I have now tried the solution with the AppDomainSetup. Now, the exception has changed to:

无法加载文件或程序集file:///C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL"或其依赖项之一.给定的程序集名称或代码库无效.(来自 HRESULT 的异常:0x80131047)
Could not load file or assembly 'file:///C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)

有什么想法吗?

推荐答案

试试这个:

namespace SeperateAppDomainTest
{
    class Program
    {
        static void Main(string[] args)
        {
            LoadAssembly();
        }

        public static void LoadAssembly()
        {
            string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
            AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
            var newDomain = AppDomain.CreateDomain("FooBar", null, domainSetup);
            ProxyClass c = (ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ProxyClass).FullName));
            Console.WriteLine(c == null);

            Console.ReadKey(true);
        }
    }

    public class ProxyClass : MarshalByRefObject { }

这篇关于在不同的 AppDomain 中加载/卸载程序集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆