如何在带有配置文件的Powershell脚本中使用自定义WCF代理

本文关键字:自定义 代理 WCF 脚本 Powershell 配置文件 | 更新日期: 2023-09-27 18:03:50

我有一个手写的WCF代理在它自己的程序集,这是非常简单的:

public class MyServiceClient : ClientBase<IMyService>, IMyService
{
    public MyServiceClient()
    {
    }
    public MyServiceClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }
}

我正在将此加载到Powershell脚本中:

Add-Type -Path "$LocalPath'MyService.Client.dll"
Add-Type -Path "$LocalPath'MyService.Contracts.dll"

然后我尝试设置App.config(根据其他帖子),以便客户端可以实例化配置中定义的端点,而不是在脚本本身:

[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "$LocalPath'MyService.Client.dll.config")

我已经检查了AppDomain,并将配置文件设置为其ConfigurationFile属性。

当我创建一个客户端实例时:

$endpointName = "MyServiceHttpEndpoint" # defined in the app.config file
$myclient = New-Object MyService.Client.MyServiceClient($endpointName)

它摔倒了,说:

Exception calling ".ctor" with "1" argument(s): "Could not find endpoint element with name 'MyServiceHttpEndpoint' and contract 'MyService.Contracts.IMyService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element."

任何想法?我不想在脚本文件中手动创建端点-它需要从config.

如何在带有配置文件的Powershell脚本中使用自定义WCF代理

读取。

Powershell和Powershell ISE处理此问题的方式似乎有所不同。

使用ISE(至少是我正在使用的版本),您必须清除配置以强制重新加载。不过,我想你也可以把你的。dll的内容。将ISE配置文件放入powershell ISE配置中。然而,这似乎令人不快。下面发布的代码可以工作。我在谷歌上找到了一部分。

# $dllPath is the path to the dll we want to load
# first point to the correct config file
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "$dllPath.config")
# PowerShell ISE is a PITA we have to override the config
if ($psISE -ne $null) {
    Add-Type -AssemblyName System.Configuration
    [Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null,0)
    [Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null,$null)
    ([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"})[0].GetField("s_current", "NonPublic, Static").SetValue($null, $null)
}
#Now load the DLL
$null = [Reflection.Assembly]::LoadFrom($dllPath)
# DLL and Config should be loaded - test

您的程序集是作为32位还是64位目标构建的?

我在很多情况下遇到了32/64问题。

只是要小心,如果你在64位操作系统上运行,你有两个powershell一个64位(通常)和一个32位(当你需要32个外部程序集时很有趣)。

如果你发布完整的配置会更容易,但听起来你错过了下面的部分。

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="ServiceAddress"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding"
        contract="MyService.Contracts.IMyService" name="MyServiceHttpEndpoint" />
    </client>
</system.serviceModel>

虽然你听起来很肯定事实并非如此。

所以让我们试着确保你的powershell应用程序正确地选择了配置…

要确保powershell应用程序是否按预期拾取配置,请在powershell文件中添加如下内容:

Get-Content $LocalPath'MyService.Client.dll.config | foreach {Write-Output $_}

如果是,那么这不是配置问题,我想我们可以达成一致。

那么dll可以看到配置中的设置吗?现在我们知道powershell可以看到配置,可以调用你的dll。

配置是否与dll在同一位置?

add-type会做一些我们意想不到的事情吗?看看msdn文档它看起来像add-type

在Windows PowerShell中添加一个microsoft.net Framework类型(一个类)会话。

如果类现在是在一个powershell会话它有访问配置像它通常会吗?我不知道。

也许可以试试[Reflection.Assembly]::LoadFromadd-type,看看是否有什么不同?

我恐怕没有确切的答案,但我希望我的漫谈能有所帮助。

似乎你错过了绑定类型,它应该是basicHttpBinding当你在powershell

让你的代码看起来像:

$endpointName = "MyServiceHttpEndpoint" 
$httpBinding = new-object System.ServiceModel.WSHttpBinding
$myclient = New-Object MyService.Client.MyServiceClient($httpBinding, $endpointName)

如果可能的话,我建议跳过配置文件。如果您的api提供了一个MEX或WSDL端点,请尝试通过查询它们来创建代理,并使用WsdlImporter在内存中构建绑定配置。从那时起,如果需要,您可以在内存中修改它。

这就是我为我所从事的项目所做的,该项目在配置WCF服务方面非常繁重,因为它使用WS-Trust与安全令牌服务集成在一起。

对于类似的问题,我建议尝试使用图库上可用的WcfPS模块。因为这个问题和另一个问题有重叠,我将引用其中的一部分。

该模块的代码是开源的,虽然它在脚本中,但它严重依赖于。net框架类和System.ServiceModelSystem.IdentityModel程序集。我之所以提到这一点,是因为这些程序集中的大多数api在。net standard 2中是不可用的,所以不幸的是,该模块不能在非windows操作系统上工作。你也可以在我的文章《WCFPS - PowerShell模块与SOAP端点一起工作》中了解更多。

这个例子来自README

#region Initialize the channel/client
$svcEndpoint="http://myserviceprovider/Service1.svc"
$wsImporter=New-WcfWsdlImporter -Endpoint $svcEndpoint -HttpGet
$proxyType=$wsImporter | New-WcfProxyType
# select the endpoint and implicitly the binding from the imported configuration
$endpoint=$wsImporter | New-WcfServiceEndpoint -Endpoint $svcEndpoint
$channel=New-WcfChannel -Endpoint $endpoint -ProxyType $proxyType
#endregion
#region Use the channel/client
$channel.Method1()
$channel.Method2()
#endregion

使用此方法,您不需要导入任何内联。net类型,也不需要在Visual Studio上使用代理,也不需要配置。最有可能的是,您将不得不调整它以适应您的用例。如果您可以改进模块的功能,请提交拉取请求。