简体   繁体   English

在不同的AppDomain中加载/卸载程序集

[英]Loading/Unloading assembly in different 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. 我知道我需要一个新的AppDomain,所以我可以卸载库。 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): 旧的非AppDomain代码看起来像这样(稍微缩短):

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: 现在我希望它们加载到自己的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. 如你所见,我已经提出了5个案例。

  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. 如果我设置事件处理程序,我得到一个异常,无法找到/加载程序集(它是管理控制台(mmc.exe)SnapIn。

  2. ExecuteAssembly does not find an entry point (well, there is none). ExecuteAssembly没有找到入口点(好吧,没有入口点)。

  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? 类似于3.如何获取程序集的名称?

  5. Same error as in 1. 与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 更新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. 无法加载文件或程序集“MyProject.SnapIn,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”或其依赖项之一。 The system cannot find the file specified. 该系统找不到指定的文件。

The file in the error message is the on loaded into mmc (the SnapIn). 错误消息中的文件是加载到mmc(SnapIn)中的文件。 Any idea how to fix this error? 知道如何修复此错误吗? AppDomain.AssemblyResolve is not called (neither in the old or new domain). 不调用AppDomain.AssemblyResolve(在旧域或新域中都不会)。

UPDATE 2 更新2

I have now tried the solution with the AppDomainSetup. 我现在尝试使用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. 无法加载文件或程序集'file:/// C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL'或其依赖项之一。 The given assembly name or codebase was invalid. 给定的程序集名称或代码库无效。 (Exception from HRESULT: 0x80131047) (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 { }

Take a look into this previous answer: How to load an assembly into different AppDomain on Windows Mobile (.NET CF) ? 请看一下之前的答案: 如何在Windows Mobile(.NET CF)上将程序集加载到不同的AppDomain中? . That answer creates a proxy class which runs into new AppDomain context so, there, you can have full control of your initialization. 该答案创建了一个代理类,它运行到新的AppDomain上下文中,因此,您可以完全控制您的初始化。

You could to create a Start() method into ServiceApplicationProxy class and just call it normally from your hoster with a proxy.Start() . 您可以在ServiceApplicationProxy类中创建一个Start()方法,并使用proxy.Start()从您的主机中正常调用它。

https://msdn.microsoft.com/en-us/library/3c4f1xde%28v=vs.110%29.aspx https://msdn.microsoft.com/en-us/library/3c4f1xde%28v=vs.110%29.aspx

specifies that 指定

typeName Type: System.String typeName类型:System.String

 The fully qualified name of the requested type, including the namespace but not the assembly, as returned by the Type.FullName 

property. 属性。

So try calling with Fully qualified name, instead of using typeof(InstanceProxy).ToString() use string/text "<<Namespace>>.InstanceProxy" 因此尝试使用完全限定名称调用,而不是使用typeof(InstanceProxy).ToString()使用字符串/文本"<<Namespace>>.InstanceProxy"

as below 如下

InstanceProxy proxy = domain.CreateInstanceAndUnwrap(path, "<<Namespace>>.InstanceProxy") as InstanceProxy;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM