将程序集加载到单独的 AppDomain 中,得到 InvalidCastException

Posted

技术标签:

【中文标题】将程序集加载到单独的 AppDomain 中,得到 InvalidCastException【英文标题】:Loading Assemblies into separate AppDomain, getting InvalidCastException 【发布时间】:2008-10-03 16:02:44 【问题描述】:

我正在尝试在单独的应用程序域中加载程序集,但遇到了一个非常奇怪的问题。这是一些代码:

    public static void LoadAssembly(string assemblyPath)
    

        string pathToDll = Assembly.GetCallingAssembly().CodeBase;
        AppDomainSetup domainSetup = new AppDomainSetup
        
            PrivateBinPath = pathToDll
        ;

        AppDomain newDomain = AppDomain.CreateDomain("AssemblyLoader",null,domainSetup);


        AssemblyLoader loader = (AssemblyLoader)newDomain.CreateInstanceFromAndUnwrap(
            pathToDll,
            typeof(AssemblyLoader).FullName);

    

AssemblyLoader 是与这个相同的程序集中的另一个类,它继承自 MarshalByRef,但是由于某些奇怪的原因,每次尝试运行它时都会遇到强制转换异常。我什至对 DLL 的路径进行了硬编码,而不是使用 GetCallingAssembly().CodeBase,但我不断收到此异常。

我知道在没有实际看到并获得更多信息的情况下很难回答这样的问题,但也许有人遇到过类似的情况并且知道常见的“陷阱”以及我应该注意什么。

编辑:我不想直接加载它的原因是因为这只是代码的一部分。最终目标是这个类将有一个方法来加载程序集,获取它们的 GUID 和一些关于它们的其他信息,并将它们存储在我正在处理的项目的数据库中。因此,如果我将此程序集加载到单独的应用程序域中,我也可以在那里加载其他程序集,然后卸载应用程序域。如果我只需要这些数据,那么在应用程序运行期间加载所有这些程序集毫无意义。

【问题讨论】:

如果AssemblyLoader 类与这个在同一个程序集中,为什么要从newDomain 加载它?为什么不直接实例化呢? 这是一种间接加载插件的方式。如果加载器实例在主应用程序域中,您在外部应用程序域中创建一个版本并要求它加载您感兴趣的插件。这可以防止您的插件需要知道它们是否能够被处理由一个单独的应用程序域。 (即从 MarshalByRefObject 派生)这使设计决策保持灵活(例如,创建一个插件基类,为插件提供所有共享功能。) 【参考方案1】:

(编辑:阅读给出的异常后,完全改变答案)

看来问题出在 CreateInstanceFromAndUnwrap 调用上,它使用了“pathToDll”的 LoadFrom 语义。 Suzanne Cook detailed the possible sticking point 在她的博客上,您的原始 AppDomain 在尝试解析有问题的类型时尝试调用 Load("SomeAssembly, [...]") 而不是 LoadFrom("pathToDll") 。

她的建议是挂钩当前域上的 AssemblyResolve 事件以执行正确的 LoadFrom 以获得类型。根据 Suzanne 的建议,进行一些有针对性的谷歌搜索会找到 a possible solution to the problem。

【讨论】:

不,这就是它的意思:无法将透明代理转换为类型 'CompanyNamespaceTakenOut.AssemblyLoader【参考方案2】:

我不认为 PrivateBinPath 配置是必要的,除此之外您不需要使用 DLL 的路径,而是第一个参数的程序集的完全限定名称;试试:

AssemblyLoader loader = (AssemblyLoader)newDomain.CreateInstanceFromAndUnwrap(
        typeof(AssemblyLoader).Assembly.FullName,
        typeof(AssemblyLoader).FullName);

【讨论】:

错误答案。 CreateInstanceFromAndUnwrap() 的第一个参数是路径和文件名,而不是程序集名称。然而,CreateInstanceAndUnwrap() 是一个程序集名称,但这对提问者没有帮助,因为它只会解析为相同的路径和文件名。【参考方案3】:

这里有很多有用的信息来说明您正在尝试做的事情:How to load a .NET assembly for reflection operations and subsequently unload it?

【讨论】:

【参考方案4】:

查看 this article.

使用那篇文章中的代码,我得到了一个跨应用程序域对象。我用泛型抽象了一些东西,并有三个程序集。 (即 1 定义接口,1 定义插件实现,以及告诉泛型加载什么的主程序。)原始文章代码很容易遵循。

【讨论】:

以上是关于将程序集加载到单独的 AppDomain 中,得到 InvalidCastException的主要内容,如果未能解决你的问题,请参考以下文章

将多个程序集版本加载到多个 AppDomain 中

是否可以避免将一些程序集加载到“AppDomain”中?

程序集无法加载到受限的 AppDomain

从 App.Config 将程序集加载到 AppDomain

将 c# 程序集动态加载和卸载到 appdomain

如何将此程序集加载到我的 AppDomain 中?