装载/卸载组件在不同的AppDomain [英] Loading/Unloading assembly in different AppDomain

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

问题描述

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

要加载的程序集是在我的插件框架插件。他们没有入口点的。我所知道的是,它们含有某些类型的其中实现给定的接口。旧的,非AppDomain- code看起来像这样(略缩短):

 尝试
{
    字符串路径= Path.GetFullPath(C:\\ library.dll);
    AppDomain.CurrentDomain.AssemblyResolve + = CurrentDomain_AssemblyResolve;
    大会ASM = Assembly.LoadFrom(路径);
    键入[]类型= asm.GetExportedTypes();
    的foreach(在类型T型)
    {
        如果((t.GetInterface(IStarter)=空)及!&放大器;!t.IsAbstract)
        {
            反对TEMPOBJ = Activator.CreateInstance(T);
            MethodInfo的信息= t.GetMethod(GetParameters);
            如果(信息!= NULL)
            {
                返回info.Invoke(TEMPOBJ,NULL)作为字符串;
            }
        }
    }
}
赶上(异常前)
{
    MessageBox.Show(的String.Format(该死的'{0}',ex.Message),异常,MessageBoxButtons.OK,MessageBoxIcon.Error);
}私人大会CurrentDomain_AssemblyResolve(对象发件人,ResolveEventArgs参数)
{
    如果(args.Name.StartsWith(MyProject.View,))
    {
        字符串路径= Path.GetFullPath(C:\\ view.dll));
        返回Assembly.LoadFrom(路径);
    }
    返回null;
}

现在我希望他们能在自己的AppDomain中加载:

 尝试
{
    字符串路径= Path.GetFullPath(C:\\ library.dll);
    AppDomain中域= AppDomain.CreateDomain(TempDomain);
    domain.AssemblyResolve + = CurrentDomain_AssemblyResolve; // 1.例外在这里!
    domain.ExecuteAssembly(路径); // 2.异常在这里!
    domain.CreateInstanceFrom(...); // 3,我不知道,该类型的命名方式。
    domain.Load(...); // 4.我不知道,该组件的命名方式。
    domain.DoCallBack(...); // 5.例外在这里!
    // ...
}
赶上(异常前)
{
    MessageBox.Show(的String.Format(该死的'{0}',ex.Message),异常,MessageBoxButtons.OK,MessageBoxIcon.Error);
}

正如你所看到的,我已经把5例。


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


  2. ExecuteAssembly没有找到一个切入点(当然,是没有的)。


  3. 我不知道该类型的命名方式。如何通过接口加载?


  4. 类似3.如何得到一个程序集的名称?


  5. 同样的错误在1。


我想问题可能是同治控制台好歹我只是不知道我在做什么错。任何帮助是AP preciated。

更新1

我现在已经使用贴代理解决方案尝试。

 的AppDomain域= AppDomain.CreateDomain(TempDomain);
InstanceProxy代理= domain.CreateInstanceAndUnwrap(Assembly.GetAssembly(
    。typeof运算(InstanceProxy))全名的typeof(InstanceProxy)的ToString())作为InstanceProxy;
如果(代理!= NULL)
{
    proxy.LoadAssembly(路径);
}
AppDomain.Unload(域);公共类InstanceProxy:MarshalByRefObject的
{
    公共无效LoadAssembly(字符串路径)
    {
        AppDomain.CurrentDomain.AssemblyResolve + = CurrentDomain_AssemblyResolve;
        大会ASM = Assembly.LoadFrom(路径);
        键入[]类型= asm.GetExportedTypes();
        // ...往上看...
    }
}

这也不起作用。当试图创建代理对象,我得到一个异常:

无法加载文件或程序集MyProject.SnapIn,版本= 1.0.0.0,文化=中性公钥= null或它的一个依赖。该系统找不到指定的文件。

在错误信息的文件是载入到MMC(管理单元中)。任何想法如何解决这个错误? AppDomain.AssemblyResolve不叫(无论是在旧的或新的域)。

更新2

我现在已经试图与AppDomainSetup解决方案。现在,除了已更改为:

无法加载文件或程序集文件:/// C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL或它的一个依赖。给定的程序集名称或codeBase的无效。 (异常来自HRESULT:0x80131047)

任何想法?


解决方案

试试这个:

 命名空间SeperateAppDomainTest
{
    类节目
    {
        静态无效的主要(字串[] args)
        {
            LoadAssembly();
        }        公共静态无效LoadAssembly()
        {
            字符串pathToDll = Assembly.GetExecutingAssembly()codeBase的。
            AppDomainSetup domainSetup =新AppDomainSetup {PrivateBinPath = pathToDll};
            VAR NEWDOMAIN = AppDomain.CreateDomain(FooBar的空,domainSetup);
            ProxyClass C =(ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll的typeof(ProxyClass).FullName));
            Console.WriteLine(C == NULL);            Console.ReadKey(真);
        }
    }    公共类ProxyClass:MarshalByRefObject的{}

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.

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;
}

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);
}

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

  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.

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

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

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

  5. 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.

UPDATE 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:

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.

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).

UPDATE 2

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

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)

Any idea?

解决方案

Try this:

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天全站免登陆