简体   繁体   English

将程序集加载到applicationBase C#的AppDomain外部站点

[英]Loading an assembly into an AppDomain outsite of applicationBase C#

So lately I've been working on a project where the application (or executable,whatever you wish to call it) needs to be able to load and unload assemblies not found within the executable's folder at all. 最近我一直致力于一个项目,其中应用程序(或可执行文件,无论你想要什么)都需要能够加载和卸载在可执行文件夹找不到的程序集 (might even be another drive) (甚至可能是另一个驱动器)

For the sake of an example , I want to be able to have my application at D:\\AAA\\theAppFolder , and the assemblies of the DLL files at C:\\BBB\\Assemblies 为了举个例子,我希望能够将我的应用程序放在D:\\ AAA \\ theAppFolder中 ,并将DLL文件的程序集放在C:\\ BBB \\ Assemblies

Looking thoroughly , I found out AppDomain allow the ability to unload themselves and any attached assemblies , so I figured I'd give it a shot, however there seems to be an issue after a few hours worth of attempts : AppDomains cannot look anywhere outside the application base. 仔细观察,我发现AppDomain允许卸载自己和任何附加程序集的能力,所以我想我会试一试,但是经过几个小时的尝试后似乎有问题:AppDomains看不到外面的任何地方应用基础。

According to AppDomain's documentary (and my own experience) you cannot set the PrivateBinPath outside of ApplicationBase , and if I set the ApplicationBase outside of the drive the application is at (via AppDomainSetup) , I get System.IO.FileNotFoundException complaining it can't find the application itself. 根据AppDomain的纪录片(以及我自己的经验)你不能在ApplicationBase之外设置PrivateBinPath,如果我在应用程序所在的驱动器之外设置ApplicationBase(通过AppDomainSetup),我得到System.IO.FileNotFoundException抱怨它不能找到应用程序本身。

Because of that I can't even reach the phase where I can use the AssemblyResolve ResolveEventHandler to attempt to get the assembly using MarhsalByRefObject inheriting classes... 因此我甚至无法达到可以使用AssemblyResolve ResolveEventHandler尝试使用MarhsalByRefObject继承类来获取程序集的阶段...

Here's a few snippets of code related to what I am currently attempting 这里有一些与我目前正在尝试的代码相关的代码片段

    internal class RemoteDomain : MarshalByRefObject
    {
        public override object InitializeLifetimeService() //there's apparently an error for marshalbyref objects where they get removed after a while without this
        {
            return null;
        }
        public Assembly GetAssembly(byte[] assembly)
        {
            try
            {
                return Assembly.Load(assembly);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }
        public Assembly GetAssembly(string filepath)
        {
            try
            {
                return Assembly.LoadFrom(filepath);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }
    }

    public static Assembly LoadAssembly(string modName, BinBuffer bb)
    {
        string assembly = pathDirTemp+"/"+modName+".dll";
        File.WriteAllBytes(assembly, bb.ReadBytes(bb.BytesLeft()));
        RemoteDomain loader = (RemoteDomain)modsDomain.CreateInstanceAndUnwrap(typeof(RemoteDomain).Assembly.FullName, typeof(RemoteDomain).FullName);
        return loader.GetAssembly(assembly);
    }

To be as specific as I can : Is there any way to get an unloadable AppDomain to load an assembly that is not within the application's base folder? 尽可能具体: 有没有办法让无法加载的AppDomain加载不在应用程序基础文件夹中的程序集?

Each AppDomain has it's own base directory and is not constrained at all by the main application base dir (unless it is the main AppDomain of the application). 每个AppDomain都有自己的基本目录,并不受主应用程序基础dir的约束(除非它是应用程序的主AppDomain)。 So you can achieve what you want using AppDomains. 因此,您可以使用AppDomains实现您想要的功能。

The reason your approach doesn't work is that you are passing Assembly objects between AppDomains. 您的方法不起作用的原因是您在AppDomains之间传递Assembly对象。 When you call any of the GetAssembly methods, the assembly will be loaded in the child AppDomain but when the method returns, the main AppDomain will try to load the Assembly as well. 当您调用任何GetAssembly方法时,程序集将加载到子AppDomain中,但是当方法返回时,主AppDomain也将尝试加载程序集。 Of course, the assembly will not be resolved because it is not in the main AppDomains's base dir , private paths or the GAC . 当然,程序集将无法解析,因为它不在主AppDomains的基本目录私有路径GAC中

So in general you should never pass Type or Assembly objects between AppDomains . 因此,通常不应在AppDomains之间传递TypeAssembly对象。

A simple way to load assemblies without leaking them to the main AppDomain can be found in this answer . 这个答案中可以找到一种加载程序集而不将它们泄漏到主AppDomain的简单方法。

Of course to make your application work with assemblies loaded in child AppDomains you will have to make MarshalByRefObject derived classes that will be your access point between AppDomains. 当然,为了使您的应用程序能够在子AppDomain中加载程序集,您必须使MarshalByRefObject派生类成为AppDomains之间的访问点。

Maybe you need to use global variable so if you use global variable to fix the problem you can declare readonly global variable for example: 也许您需要使用全局变量,因此如果您使用全局变量来修复问题,您可以声明readonly全局变量,例如:

public static string a = "Moosaie";

Convert it to 将其转换为

public static readonly a = "Moosaie";

Anyway you can not use global dynamic value variable for CLR assembly. 无论如何,您不能将全局动态值变量用于CLR程序集。

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

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