将 DLL 加载到单独的 AppDomain 中

发布于 2024-10-08 23:08:00 字数 691 浏览 8 评论 0原文

我正在编写一个插件架构。我的插件 dll 位于运行插件管理器的子目录中。 我将插件加载到单独的 AppDomain 中,如下所示:

string subDir;//initialized to the path of the module's directory.
AppDomainSetup setup = new AppDomainSetup();
setup.PrivateBinPath = subDir;
setup.ApplicationBase = subDir;

AppDomain newDomain= AppDomain.CreateDomain(subDir, null, setup);

byte[] file = File.ReadAllBytes(dllPath);//dll path is a dll inside subDir
newDomain.Load(file);

但是。 newDomain.Load 返回当前域尝试加载的程序集。因为插件 dll 位于子目录中,所以当前域不能也不应该看到这些 dll,并且当前域会抛出 FileLoadException "ex = {"无法加载文件或程序集...或其依赖项之一。"

问题是,我们可以将程序集加载到单独的 AppDomain 中而不返回加载的程序集吗?

我知道我可以为当前域中的 AssemblyResolve 事件并返回 null,但我不想走这条路

I am writing a plugin architecture. My plugin dlls are located in a sub directory from where the plugin manager is running.
I am loading the plugins into a separate AppDomain as the following:

string subDir;//initialized to the path of the module's directory.
AppDomainSetup setup = new AppDomainSetup();
setup.PrivateBinPath = subDir;
setup.ApplicationBase = subDir;

AppDomain newDomain= AppDomain.CreateDomain(subDir, null, setup);

byte[] file = File.ReadAllBytes(dllPath);//dll path is a dll inside subDir
newDomain.Load(file);

However. newDomain.Load returns an assembly which the currently domain attempts to load. Because the plugin dlls are in a sub directory, the current domain cannot and should not see these dlls and the current domain throws a FileLoadException
"ex = {"Could not load file or assembly ... or one of its dependencies."

The question is, can we load an assembly into a separate AppDomain without it returning the loaded assembly?

I know I can add a handler for the AssemblyResolve event in the current domain and return a null, but I would prefer to not to go this route.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

伪心 2024-10-15 23:08:00

您还可以使用 DoCallBack - 这是我在阅读了很多有关它的内容后整理的内容。这将创建一个应用程序域,检查程序集是否具有相同的签名公钥,加载程序集,执行静态方法,卸载应用程序域,然后删除 dll。

static void Main(string[] args)
    {
        string unknownAppPath = @"path-to-your-dll";

        Console.WriteLine("Testing");
        try
        {
            AppDomainSetup setup = new AppDomainSetup();
            setup.AppDomainInitializer = new AppDomainInitializer(TestAppDomain);
            setup.AppDomainInitializerArguments = new string[] { unknownAppPath };
            AppDomain testDomain = AppDomain.CreateDomain("test", AppDomain.CurrentDomain.Evidence, setup);
            AppDomain.Unload(testDomain);
            File.Delete(unknownAppPath);
        }
        catch (Exception x)
        {
            Console.WriteLine(x.Message);
        }
        Console.ReadKey(); 
    }

    public static void TestAppDomain(string[] args)
    {
        string unknownAppPath = args[0];
        AppDomain.CurrentDomain.DoCallBack(delegate()
        {
            //check that the new assembly is signed with the same public key
            Assembly unknownAsm = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(unknownAppPath));
            //get the new assembly public key
            byte[] unknownKeyBytes = unknownAsm.GetName().GetPublicKey();
            string unknownKeyStr = BitConverter.ToString(unknownKeyBytes);
            //get the current public key
            Assembly asm = Assembly.GetExecutingAssembly();
            AssemblyName aname = asm.GetName();
            byte[] pubKey = aname.GetPublicKey();
            string hexKeyStr = BitConverter.ToString(pubKey);
            if (hexKeyStr == unknownKeyStr)
            {
                //keys match so execute a method
                Type classType = unknownAsm.GetType("namespace.classname");
                classType.InvokeMember("method-you-want-to-invoke", BindingFlags.InvokeMethod, null, null, null);
            }
        });
    }

You can also use DoCallBack - here's something I put together after reading lots about it on SO. This creates an appdomain, checks that the assemblies have the same signature public key, loads the assembly, executes a static method, unloads the appdomain, then deletes the dll.

static void Main(string[] args)
    {
        string unknownAppPath = @"path-to-your-dll";

        Console.WriteLine("Testing");
        try
        {
            AppDomainSetup setup = new AppDomainSetup();
            setup.AppDomainInitializer = new AppDomainInitializer(TestAppDomain);
            setup.AppDomainInitializerArguments = new string[] { unknownAppPath };
            AppDomain testDomain = AppDomain.CreateDomain("test", AppDomain.CurrentDomain.Evidence, setup);
            AppDomain.Unload(testDomain);
            File.Delete(unknownAppPath);
        }
        catch (Exception x)
        {
            Console.WriteLine(x.Message);
        }
        Console.ReadKey(); 
    }

    public static void TestAppDomain(string[] args)
    {
        string unknownAppPath = args[0];
        AppDomain.CurrentDomain.DoCallBack(delegate()
        {
            //check that the new assembly is signed with the same public key
            Assembly unknownAsm = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(unknownAppPath));
            //get the new assembly public key
            byte[] unknownKeyBytes = unknownAsm.GetName().GetPublicKey();
            string unknownKeyStr = BitConverter.ToString(unknownKeyBytes);
            //get the current public key
            Assembly asm = Assembly.GetExecutingAssembly();
            AssemblyName aname = asm.GetName();
            byte[] pubKey = aname.GetPublicKey();
            string hexKeyStr = BitConverter.ToString(pubKey);
            if (hexKeyStr == unknownKeyStr)
            {
                //keys match so execute a method
                Type classType = unknownAsm.GetType("namespace.classname");
                classType.InvokeMember("method-you-want-to-invoke", BindingFlags.InvokeMethod, null, null, null);
            }
        });
    }
一梦浮鱼 2024-10-15 23:08:00

正如下面给出的链接所指出的:

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

< a href="https://stackoverflow.com/questions/2715104/load-assemble-in-new-appdomain-without-loading-it-in-parent-appdomain">在新 AppDomain 中加载程序集,而不在父 AppDomain 中加载它

似乎在另一个 AppDomain 对象上调用 Load() 方法也会导致该程序集加载到当前的 AppDomain 中。

解决方案是使用 AppDomain 类的 CreateInstanceFromAndUnwrap() 方法。您传递程序集的路径和要转换为的类型。

As pointed out in links given below:

Loading/Unloading assembly in different AppDomain

Load Assembly in New AppDomain without loading it in Parent AppDomain

It seems that calling Load() method on another AppDomain object causes that assembly to be loaded in current AppDomain as well.

The solution is to use CreateInstanceFromAndUnwrap() method of AppDomain class instead. You pass a path to assembly and a type to be converted to.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文