PowerShell 7中的ORACLE ManagedDataAccess核心

gpnt7bae  于 2023-10-16  发布在  Oracle
关注(0)|答案(1)|浏览(103)

我有一个简单的.NET 7类库引用这个NuGet包(不包括其他ORACLE包):

<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.100" />

然后我有一个用C#编写的PowerShell模块(也针对.NET 7)。它引用了上述项目。

<ProjectReference Include="..\Core\Core.csproj" />

PowerShell模块只有一个小程序Test-Oracle。它从Core.dll调用一个方法。方法尝试连接到ORACLE并执行SELECT * FROM dual
在我的机器上工作得很好-它连接到ORACLE并输出数据。我的客户端,运行相同的代码,得到这个异常:

System.TypeLoadException: Could not load type 'System.Security.Principal.WindowsImpersonationContext' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral......

有什么办法解决吗?

编辑:

“核心”项目,实际查询到ORACLE,引用这些NuGet包:

<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.100" />
<PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="serilog.sinks.console" Version="4.1.0" />
<PackageReference Include="serilog.sinks.file" Version="5.0.0" />

PowerShell模块项目包括:

<ItemGroup>
   <PackageReference Include="PowerShellStandard.Library" Version="5.1.0-preview-06">
      <PrivateAssets>All</PrivateAssets>
   </PackageReference>
</ItemGroup>

<ItemGroup>
    <ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
mbjcgjjk

mbjcgjjk1#

前言

  • 下面的答案并不能解决这个问题,但是对于编写应该只在PowerShell (Core) 7+中使用的PowerShell模块可能会有兴趣,即应该拒绝在 Windows PowerShell 中加载。
  • 为了进一步缩小问题的范围,我建议实现一个assembly-resolve event handler并记录结果:
  • 当运行库本身无法找到请求加载的程序集时,将调用该函数。
  • event-arguments对象的ResolveEventArgs.RequestingAssembly属性包含 * 请求 * 加载的程序集。

我可能没有完整的图片,但我的理解是这样的:
您使用的是PowerShellStandard.Library NuGet package,这意味着您的PowerShell模块(小工具)* 也可以在Windows PowerShell* 中运行,而不仅仅是在PowerShell (Core) 7+中。

    • 可以想象 *,问题是由于您的客户端在 Windows PowerShell 中运行模块引起的,导致尝试引用.NET(Core)System.Security.Principal.WindowsImpersonationContext类型-请参阅this GitHub issue了解背景。

但是,为了创建一个可以在 * 常规PowerShell会话 * 中使用的PowerShell模块,(而不是创建一个本身托管PowerShell的应用程序),你 * 必须 * 使用PowerShellStandard.Library包-但是我知道 * 没有 * 内置的方法来 * 限制模块只能在一个版本或另一个版本中运行 *(GitHub issue #5541的主题是在未来提供更好的目标定位)。
因此,如果你想强制你的模块只能在PowerShell(Core)中使用,你必须自己实现:[1]

  • 二进制PowerShell模块支持在加载(导入)模块时调用的初始化挂钩。
  • 在该钩子中,您可以测试您是在.NET Framework(意味着 Windows PowerShell)还是.NET(Core)(意味着 PowerShell(Core))中运行。如果是前者,你可以抛出一个异常。

这里有一个概念验证,使用ad编译的C#代码来简化:

Add-Type @'
using System.Management.Automation;

namespace YourNamespace {
  // Initialization hook.
  public class MyModuleAssemblyInitializer : IModuleAssemblyInitializer
  {
      public void OnImport()
      {
          // Test if the runtime is .NET Framework, which implies Windows PowerShell,
          // and throw an exception if so.
          if (System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework ")) 
          {
            throw new System.PlatformNotSupportedException("This module supports PowerShell (Core) only; it cannot run in Windows PowerShell.");
          }
      }
  }
  
  // Sample cmdlet.
  [Cmdlet("Get", "Foo")]
  public class GetFooCmdlet : PSCmdlet {
    protected override void ProcessRecord() {
      WriteObject("Hi from Get-Foo");
    }
  }

}
'@ -PassThru | ForEach-Object Assembly | Import-Module
  • 如果您在PowerShell(核心)会话中执行上述操作,导入应该会成功,并且之后应该能够调用Get-Foo
  • 如果在 Windows PowerShell 会话中执行,则应抛出PlatformNotSupportedException异常。

[1]注意:尽管PowerShell module manifests有一个CompatiblePSEditions条目来声明版本兼容性,但它似乎具有纯粹的 * 信息 * 字符,并且 * 不强制执行 *,最高可达PowerShell(Core)7.3.7(撰写本文时的当前版本)。目前,在尝试导入 Windows PowerShell 的 * 系统模块 * 时,该条目 * 仅 * 受到尊重,即这些存储在$env:windir\System32\WindowsPowerShell\v1.0\Modules中,在 PowerShell(核心) 中。

相关问题