Powershell配置程序集重定向

时间:2014-06-12 09:58:41

标签: .net powershell assembly-resolution

我有一个自定义.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,但它似乎没有获得重定向。

在这里难以理解解决方案。任何线索可能是什么问题?同样的重定向在我的一些商业服务中起作用,否则会出现同样的问题(他们也使用第三方库和json.net 6)。

干杯

2 个答案:

答案 0 :(得分:22)

不确定它是如何在一年多以前工作的,但是今天在Windows 10上使用PowerShell 5.0.10240.16384我能够进行程序集重定向(在我的情况下从FSharp.Core 4.3到4.4)的唯一方法是手动根据{{​​3}}解决程序集依赖关系。我尝试了其他所有解决方案,例如创建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中的版本已经过时了(我想这可能也是你的情况)

您也可以Manually resolving assembly dependencies in PowerShell

答案 1 :(得分:0)

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

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

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

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 元素进行重定向。