首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何以递归方式将所有引用的程序集加载到AppDomain?

如何以递归方式将所有引用的程序集加载到AppDomain?
EN

Stack Overflow用户
提问于 2009-03-18 14:30:10
回答 8查看 143.1K关注 0票数 116

我想加载到一个新的具有复杂引用树的AppDomain程序集(MyDll.dll -> Microsoft.Office.Interop.Excel.dll -> Microsoft.Vbe.Interop.dll -> Office.dll -> stdole.dll)

据我所知,当程序集被加载到AppDomain时,它的引用不会自动加载,我必须手动加载它们。所以当我这样做的时候:

代码语言:javascript
复制
string dir = @"SomePath"; // different from AppDomain.CurrentDomain.BaseDirectory
string path = System.IO.Path.Combine(dir, "MyDll.dll");

AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = dir;
AppDomain domain = AppDomain.CreateDomain("SomeAppDomain", null, setup);

domain.Load(AssemblyName.GetAssemblyName(path));

并得到了FileNotFoundException

无法加载文件或程序集“MyDll,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”或其依赖项之一。系统找不到指定的文件。

我认为最关键的部分是它的依赖之一的

好的,在domain.Load(AssemblyName.GetAssemblyName(path));之前我会做下一步

代码语言:javascript
复制
foreach (AssemblyName refAsmName in Assembly.ReflectionOnlyLoadFrom(path).GetReferencedAssemblies())
{
    domain.Load(refAsmName);
}

但是在另一个(引用的)程序集上再次获得了FileNotFoundException

如何以递归方式加载所有引用?

在加载根程序集之前,我必须创建引用树吗?如何在不加载的情况下获取程序集的引用?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2012-11-13 12:43:51

在外部应用程序域中执行代理对象之前,您需要调用CreateInstanceAndUnwrap

代码语言:javascript
复制
 class Program
{
    static void Main(string[] args)
    {
        AppDomainSetup domaininfo = new AppDomainSetup();
        domaininfo.ApplicationBase = System.Environment.CurrentDirectory;
        Evidence adevidence = AppDomain.CurrentDomain.Evidence;
        AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);

        Type type = typeof(Proxy);
        var value = (Proxy)domain.CreateInstanceAndUnwrap(
            type.Assembly.FullName,
            type.FullName);

        var assembly = value.GetAssembly(args[0]);
        // AppDomain.Unload(domain);
    }
}

public class Proxy : MarshalByRefObject
{
    public Assembly GetAssembly(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFile(assemblyPath);
        }
        catch (Exception)
        {
            return null;
            // throw new InvalidOperationException(ex);
        }
    }
}

另外,请注意,如果您使用LoadFrom,您可能会得到一个FileNotFound异常,因为程序集解析器将尝试查找您在GAC或当前应用程序的bin文件夹中加载的程序集。改为使用LoadFile加载任意程序集文件--但请注意,如果这样做,您将需要自己加载任何依赖项。

票数 71
EN

Stack Overflow用户

发布于 2010-06-17 14:10:36

http://support.microsoft.com/kb/837908/en-us

C#版本:

创建一个版主类并从MarshalByRefObject继承它

代码语言:javascript
复制
class ProxyDomain : MarshalByRefObject
{
    public Assembly GetAssembly(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFrom(assemblyPath);
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException(ex.Message);
        }
    }
}

从客户端站点调用

代码语言:javascript
复制
ProxyDomain pd = new ProxyDomain();
Assembly assembly = pd.GetAssembly(assemblyFilePath);
票数 13
EN

Stack Overflow用户

发布于 2013-12-05 21:30:06

一旦您将程序集实例传递回调用方域,调用方域将尝试加载它!这就是你得到异常的原因。这发生在最后一行代码中:

代码语言:javascript
复制
domain.Load(AssemblyName.GetAssemblyName(path));

因此,无论你想对程序集做什么,都应该在一个代理类中完成--一个继承MarshalByRefObject的类。

考虑到调用方域和新创建的域都应该有权访问代理类程序集。如果您的问题不是太复杂,请考虑保持ApplicationBase文件夹不变,这样它将与调用方域文件夹相同(新域将只加载它需要的程序集)。

用简单的代码:

代码语言:javascript
复制
public void DoStuffInOtherDomain()
{
    const string assemblyPath = @"[AsmPath]";
    var newDomain = AppDomain.CreateDomain("newDomain");
    var asmLoaderProxy = (ProxyDomain)newDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(ProxyDomain).FullName);

    asmLoaderProxy.GetAssembly(assemblyPath);
}

class ProxyDomain : MarshalByRefObject
{
    public void GetAssembly(string AssemblyPath)
    {
        try
        {
            Assembly.LoadFrom(AssemblyPath);
            //If you want to do anything further to that assembly, you need to do it here.
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException(ex.Message, ex);
        }
    }
}

如果确实需要从与当前应用程序域文件夹不同的文件夹加载程序集,请使用特定的dll搜索路径文件夹创建新的应用程序域。

例如,上面代码中的应用程序域创建行应该替换为:

代码语言:javascript
复制
var dllsSearchPath = @"[dlls search path for new app domain]";
AppDomain newDomain = AppDomain.CreateDomain("newDomain", new Evidence(), dllsSearchPath, "", true);

这样,所有的dlls都将自动从dllsSearchPath中解析。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/658498

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档