我有一个“核心”程序集,其中包含一系列用 C# 编写的 PowerShell Cmdlet。我还有一个使用这个“核心”程序集的 WPF“gui”应用程序。为了使用和编译“核心”,我显然需要 PowerShell 的类型,因此我添加了对System.Management.Automation.dll
我的项目的引用。我通过简单地从我的本地机器 GAC 添加对该 DLL 的引用来做到这一点。一切都在我的机器上编译并顺利运行。
当我在另一台机器上部署和运行我的“gui”时,我得到了奇怪的错误。例如:
System.MissingMethodException: Method not found: 'System.Management.Automation.PSDataCollection`1<System.Management.Automation.InformationRecord> System.Management.Automation.PSDataStreams.get_Information()'
我已将原因缩小到这一点:我的“gui”实现了一个自定义 PowerShell 主机并加载“核心”并执行它的 cmdlet。它是这样完成的:
Host = new MyCustomHost();
var rs = RunspaceFactory.CreateRunspace(Host);
PsInstance = PowerShell.Create();
PsInstance.Runspace = rs;
rs.Open();
PsInstance.Streams.Information.DataAdded += delegate (object s, DataAddedEventArgs e)
{
nvtLogger.WriteInformation(PsInstance.Streams.Information[e.Index].MessageData.ToString());
};
显然,PsInstance.Streams.Information
在运行时找不到该属性。
我发现System.Management.Automation.dll
我作为项目参考添加的那个不一定是加载的那个。该框架首先查看 GAC,如果它在那里找到一个副本,它会使用那个副本而不是我的副本。
我知道问题的原因是部署机器安装了旧版本的 PowerShell,它没有实现我正在使用的属性 - 并引发上述异常。
然而,我不明白的是:当它与我构建的程序集不兼容时,框架如何从 GAC 加载这个程序集?
据我所知,该框架使用 AssemblyVersion、Name 和 PublicKeyToken 来识别程序集。
我的本地集会(工作):
Assembly Location: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
Assembly Fullname: System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
File ProductVersion: 10.0.14393.1532
File Size: 7,1MB
服务器组件(不工作):
Assembly Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
Assembly Fullname: System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
File ProductVersion: 6.3.9600.18728
File Size: 5,8MB
这两个文件无疑是不同的。但根据 AssemblyName,它们是相同的。这样,框架将加载一个或另一个。
两个明显不同的文件(即使只看文件的大小)怎么会有相同的 AssemblyName 呢?
我想补充一点,目标机器是 Windows Server 2012R2,但它并不是我注意到这一点的唯一机器。我还在新安装的 Windows 7 和另一个 Windows 2012 Server 上注意到它。