【问题标题】:Powershell config assembly redirectPowershell 配置程序集重定向
【发布时间】:2014-08-02 14:39:09
【问题描述】:

我有一个自定义 .NET 程序集,其中包含一些 powershell cmdlet,而不是用于常见域相关任务。我刚刚创建了一个新的 cmdlet,它引用了一个引用了 Newtonsoft.Json 4.5.0.0 的第三方库。然而,我的其他项目之一使用最新版本的 json.net (6.0.0.0)。所以在 powershell fusion 运行时会抛出一个错误,说它无法加载 newtonsoft.json 4.5.0.0。

我已经尝试创建一个 powershell.exe.config 并在其中放置一个程序集重定向:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json", Culture=neutral,     PublicKeyToken=30ad4fe6b2a6aeed/>
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

但这似乎不起作用。融合日志确实表明它正在寻找这个新的 powershell 配置文件,但它似乎没有接收到重定向。

这里有点难找解决方案。任何线索可能是什么问题?同样的重定向适用于我的一些业务服务,否则它们会遇到同样的问题(他们也使用这个 3rd 方库和 json.net 6)。

干杯

【问题讨论】:

    标签: .net powershell assembly-resolution


    【解决方案1】:

    不知道一年多以前它是如何工作的,但是今天在使用 PowerShell 5.0.10240.16384 的 Windows 10 上,我能够进行程序集重定向的唯一方法(在我的情况下从 FSharp.Core 4.3 到 4.4)是手动解析程序集基于Manually resolving assembly dependencies in PowerShell 的依赖项。我尝试了所有其他解决方案,例如创建powershell.exe.config 文件或尝试加载其他一些*.config file,但这些都不起作用。

    唯一的“问题”(至少对我来说)是,因为我没有在任何地方都有 FSharp.Core 4.3,我需要手动将其重定向到 4.4。我最终使用了

    $FSharpCore = [reflection.assembly]::LoadFrom($PSScriptRoot + "\bin\LIBRARY\FSharp.Core.dll") 
    
    $OnAssemblyResolve = [System.ResolveEventHandler] {
      param($sender, $e)
    
      # from:FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
      # to:  FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
      if ($e.Name -eq "FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") { return $FSharpCore }
      
      foreach($a in [System.AppDomain]::CurrentDomain.GetAssemblies())
      {
        if ($a.FullName -eq $e.Name)
        {
          return $a
        }
      }
      return $null
    }
    
    [System.AppDomain]::CurrentDomain.add_AssemblyResolve($OnAssemblyResolve)
    

    我首先从某处加载正确版本的 FSharp.Core,因为 GAC 中的版本很旧(我想这也可能是你的情况)

    你也可以check the real test usage in my project

    【讨论】:

    • 已经是 2017 年 9 月,我确认这是唯一有效的解决方案,也适用于 Windows Server 2016。谢谢您!
    • 这非常适合我。请注意,它在 PowerShell(包括 Visual Studio 代码中的 PowerShell 窗口)中有效,但在 PowerShell ISE(或 Visual Studio Code 中的 PowerShell 集成控制台)中无效——后者可能会遇到堆栈溢出或未知原因的崩溃。
    【解决方案2】:

    我发现尝试使用[System.AppDomain]::CurrentDomain.add_AssemblyResolve 在 PowerShell 中附加处理程序来解析程序集可能会导致问题,尤其是在 PowerShell ISE 中。

    或者,这可以通过实现IModuleAssemblyInitializer 接口在根模块程序集(包含PSCmdlet 类)中处理。

    以接受的答案为例,可以改写为:

    public class ModuleInitializer : IModuleAssemblyInitializer
    {
        public void OnImport()
        {
            var fSharpCore = Assembly.LoadFrom(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "FSharp.Core.dll"));
    
            AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs e) =>
            {
                // from:FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
                // to:  FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
                if (e.Name == "FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") { return fSharpCore; }
    
                foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
                {
                    if (a.FullName == e.Name)
                    {
                        return a;
                    }
                }
    
                return null;
            };
        }
    }
    

    在我的例子中,我使用这种机制来查找伴随的.dll.config 并根据dependentAssembly/bindingRedirect 元素进行重定向。

    【讨论】:

    猜你喜欢
    • 2014-12-26
    • 2023-01-11
    • 2017-09-26
    • 1970-01-01
    • 2011-02-25
    • 2012-04-27
    • 2017-02-16
    • 1970-01-01
    • 2010-09-06
    相关资源
    最近更新 更多