Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.Net-托管可执行文件是否在启动时获取GAC的快照?_.net_Reflection_Gac_.net Assembly - Fatal编程技术网

.Net-托管可执行文件是否在启动时获取GAC的快照?

.Net-托管可执行文件是否在启动时获取GAC的快照?,.net,reflection,gac,.net-assembly,.net,Reflection,Gac,.net Assembly,我在开发一个应用程序时遇到了这个问题,该应用程序按需(单击按钮)将程序集安装到GAC,并尝试在单击下一个按钮时加载程序集,或尝试从新的GAC程序集调用方法,但失败了。问题和修复步骤如下 问题和重做步骤: 创建一个新类库,类似于下面的名为FooGreet.dll的类库,并对其进行强名称命名。让我们稍后将其拖动到程序集文件夹 namespace FooGreet { public class Greeting { public string SayHello()

我在开发一个应用程序时遇到了这个问题,该应用程序按需(单击按钮)将程序集安装到GAC,并尝试在单击下一个按钮时加载程序集,或尝试从新的GAC程序集调用方法,但失败了。问题和修复步骤如下

问题和重做步骤: 创建一个新类库,类似于下面的名为FooGreet.dll的类库,并对其进行强名称命名。让我们稍后将其拖动到程序集文件夹

namespace FooGreet
{
    public class Greeting
    {
        public string SayHello()
        {
            return "Hello";
        }
    }
}
创建控制台应用程序以加载上述类库,类似于以下代码

namespace FooGreetCaller
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press Enter to load assembly..");
            while (true)
            {
                string input = Console.ReadLine();
                if (input == "q" || input == "Q")
                    break;
                try
                {
                    System.Reflection.Assembly.Load("FooGreet, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=3f330bcf59df56c9");
                    Console.WriteLine("Assembly load success.");
                }
                catch (Exception eX)
                {
                    Console.WriteLine(eX.Message + Environment.NewLine + eX.StackTrace);
                }
            }
        }
    }
}
  • 运行控制台应用程序: 运行控制台应用程序的实例。尝试加载FooGreet.dll,无论加载多少次,都会出现“无法加载文件或程序集…”的异常。不要关闭控制台窗口
  • 将FooGreet.dll安装到GAC: 将FooGreet.dll拖动到GAC,在控制台应用程序的同一实例上,再次尝试加载FooGreet.dll,仍然会得到相同的异常;我称之为异常,因为FooGreet.dll在GAC中,控制台应用程序应该已经识别它。不应该吗
  • 运行控制台应用程序的第二个实例: 运行控制台应用程序的第二个实例。尝试加载FooGreet.dll,现在程序集加载正常
  • 从GAC卸载FooGreet.dll: 转到GAC,卸载FooGreet.dll。尝试在控制台应用程序的第二个实例中再次加载FooGreet.dll。程序集已成功加载。理想情况下,它不应该抛出类似“无法加载文件或程序集…”这样的异常吗
  • 问题: 问题在第2步和第4步。从第2步和第4步的情况来看,当应用程序加载时,它会拍摄GAC的快照(至少对于默认的AppDomain,我还没有尝试创建和加载新的AppDomain)。这是真的吗

    (在我的应用程序中,作为一种解决方法,我在向GAC注册特定程序集后重新启动应用程序

    System.EnterpriseServices.Internal.Publish().GacInstall(targetAssemblyName);
    

    我使用的是WinForms应用程序,我正在表单加载中重新启动,这会导致主表单闪烁几秒钟。我不喜欢这一点)

    程序集绑定器实际上使用缓存。代码中请求的任何程序集,程序集绑定器都遵循其加载程序集的过程。程序集绑定的结果由程序集绑定器缓存。当再次请求相同的程序集时,程序集绑定器将在缓存中查找,如果程序集已正确加载,则返回对已加载程序集的引用,如果程序集绑定失败,则返回异常

    需要注意的另一点是,绑定上下文也用于缓存
    Assembly.Load
    Assembly.LoadFrom
    Assembly.Load(字节[])
    ,这3种方法使用3种不同的绑定上下文,缓存分别存储在每个加载类型进程中。但是,推荐的方法是
    Assembly.Load

    要验证所有这些,您可以在计算机上启用fusion,并在中查看绑定结果。

    虽然“快照”一词看起来不准确,但它并不准确。程序集加载器只记住所有assembly.Load/From()请求。包括失败的。并确保它始终如一地返回相同的结果。包括失败的。这是一项强有力的反腐败措施

    使用场景非常奇怪,因此很难找到解决方法。无法强制重置“我以前见过加载”状态。但是NET 1.x没有这样做,因此有一个app.exe.config设置可用于还原1.x行为。使用。但请注意,这会产生全球性影响


    要将其本地化为仅此一个程序集,您可以创建一个AppDomain,尝试将该程序集加载到其中并再次卸载。然后,您将知道加载到主域中是否会失败。

    如果我使用的是程序集的全名(而不是部分名称),则我对使用此名称、版本、区域性和publickeytoken加载此程序集的CLR非常特别。如果LoadFrom()支持程序集的部分名称,则如果程序集加载程序不记得以前的请求,则可能存在DLL地狱。我想我是对的。如果我错了,请纠正我。这与文件不存在有什么关系?什么都没有。我试图理解“这是一个强大的反DLL地狱计数器措施”这句话,+1提到了AppDomain细节和“DLL地狱计数器措施”。自从他第一个来,我就把贾格斯作为答案。