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

时间:2020-03-06 15:05:01  来源:igfitidea点击:

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

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,但是由于某些奇怪的原因,每次尝试运行此程序时,都会得到强制转换异常。我什至没有使用GetCallingAssembly()。CodeBase来对DLL的路径进行硬编码,但我不断收到此异常。

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

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

解决方案

我认为PrivateBinPath配置不是必需的,除此之外,我们不需要使用DLL的路径,而只需使用Assembly的第一个参数的标准名称即可;尝试:

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

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

看来问题出在CreateInstanceFromAndUnwrap调用,该调用使用'pathToDll'的LoadFrom语义。 Suzanne Cook在她的博客上详细介绍了可能的症结所在,原始AppDomain尝试在尝试解析有问题的类型时尝试调用Load(" SomeAssembly,[...]")而不是LoadFrom(" pathToDll")。

她的建议是挂钩当前域上的AssemblyResolve事件以执行正确的LoadFrom以获得类型。根据Suzanne的建议,有针对性的一点点谷歌搜索为该问题提出了一种可能的解决方案。

我们在这里尝试执行的操作有很多有用的信息:如何为反射操作加载.NET程序集并随后将其卸载?

查看这篇文章。

使用该文章中的代码,我得到了一个跨应用程序域的对象。我使用泛型对事物进行了抽象,并具有三个程序集。 (即1个定义了接口,1个定义了插件的实现,以及告诉通用类要加载什么的主程序。)原始文章的代码很容易理解。