Powershell:使用 MTOM 消息编码使用 WCF 服务时出错

Posted

技术标签:

【中文标题】Powershell:使用 MTOM 消息编码使用 WCF 服务时出错【英文标题】:Powershell: Error consuming WCF services with MTOM message encoding 【发布时间】:2011-07-31 04:15:08 【问题描述】:

我目前正在探索 powershell 功能,但遇到了一个我无法解决的问题。任何快速提示将不胜感激 =)

我的目标: 从 powershell v2.0(希望使用 new-webserviceproxy cmdlet)调用 WCF 服务(配置了 MTOM 消息编码)的方法

我的问题: 当消息编码设置为 Mtom 时,new-webserviceproxy cmdlet 无法正确解析服务的响应。我收到以下错误:

PowerShell

$proxyObject = New-WebServiceProxy -URI "@987654321@" $proxyObject.TestWebServiceConnection()

使用“0”参数调用“TestWebServiceConnection”的异常:“客户端发现响应内容类型为'multipart/related; type="application/xop+xml";start="&lthttp://tempuri.org/0&gt";边界=“uuid: 4001d529-32b9-4560-9f4b-550c35c67b03+id=4";start-info="text/xml"',但预期为 'text/xml'。 请求失败并显示错误消息: -- --uuid:4001d529-32b9-4560-9f4b-550c35c67b03+id=4 内容 ID:&lthttp://tempuri.org/0&gt 内容传输编码:8bit 内容类型:application/xop+xml;charset=utf-8;type="text/xml" &lts:信封 xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt &lts:身体&gt &ltTestWebServiceConnectionResponse xmlns="http://myserver.com/"&gt &ltTestWebServiceConnectionResult&gt成功&lt/TestWebServiceConnectionResult&gt &lt/TestWebServiceConnectionResponse&gt &lt/s:身体&gt &lt/s:信封&gt --uuid:4001d529-32b9-4560-9f4b-550c35c67b03+id=4-- --。” 在 line:1 char:38 + $proxyObject.TestWebServiceConnection &lt&lt&lt&lt () &gt&gt error.txt + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodException

注意 我可以通过其他客户端甚至微软提供的 wcfclient 工具来使用 WCF 服务。您可以看到 TestWebServiceConnectionResult 返回了 success,但代理对象似乎无法解析响应。

行为

&lt服务行为&gt &ltbehavior name="MyServiceBehavior"&gt &ltserviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100"/&gt &ltserviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/&gt &ltserviceDebug includeExceptionDetailInFaults="false"/&gt &lt/行为&gt &lt/服务行为&gt

绑定(我已经排除了超时值/阅读器配额和消息大小,因为它们的值的排列似乎与我的问题无关):

&ltbasicHttpBinding&gt &ltbinding name="basicHttpEndpointBinding" messageEncoding="Mtom"&gt &ltsecurity mode="无"&gt &lttransport clientCredentialType="None"/&gt &lt/安全&gt &lt/basicHttpBinding&gt

服务

&ltservice behaviorConfiguration="MyServiceBehavior" name="MyService.AccessService"&gt &ltendpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" name="basicHttpEndpointAccessService" bindingNamespace="http://myserver.com/" contract="MyService.IAccessService"/&gt &ltendpoint address="mex" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" name="mexEndpointAccess" contract="IMetadataExchange"/&gt &lt/服务&gt

【问题讨论】:

作为一个测试,你能不能把服务消息编码改为文本,看看它是否开始工作? (这将证明 MTOM 编码是问题的根源) 我认为发送和接收时 WCF 的编码必须相同(参见***.com/questions/284149/…)。 New-WebServiceProxy 可能只使用 text/xml。您可以尝试在 .NET 中创建一个调用该服务的包装类,并在 PowerShell 中使用该类? Bob,我确实相信是这种情况,但我似乎找不到任何类型的属性可以让我设置此 cmdlet 返回的对象使用的消息编码。在 .Net 中创建包装器方法可能会起作用(只是有点失望,因为已经提供的 cmdlet 无法做到这一点)。我实际上倾向于在 powershell 中编写一些函数来调用 wsdl 上的 svcutil,编译生成的代理类,然后指定我自己的绑定(具有所需的配置)和端点。 【参考方案1】:

截至撰写本文时,我仍然无法成功使用 New-WebServiceProxy cmdlet 和启用了 MTOM 的 WCF 服务;它看起来不像 cmdlet 支持它。我的解决方法是针对 wsdl 运行 svcutil.exe,然后使用 csc.exe 将类编译为 dll。然后我将生成的程序集加载到powershell运行时,然后手动配置代理类的端点和绑定:

从您的 wsdl 生成 .cs 文件:

$svcUri = "http://yourdomain/yourService.svc?wsdl";
$csFile = $className + '.cs';   # The name of the generated .cs file
$dllName = [System.IO.Path]::Combine($temp, $className + ".dll")
$svcUtilresult = svcutil.exe /noConfig /out:$csFile $svcUri

注意 svcutil.execsc.exe 可能不在你的 powershell 路径中。您可以将其添加到 PATH 或使用完整路径。 Svcutil 可以在您的 Microsoft SDKs\Windows\<version>\bin 中找到。 csc.exe 位于您的 %windir%Microsoft .Net 文件夹中

生成 .cs 文件后,您需要将其编译为 dll:

&"csc.exe" /t:library /out:$dllName $csFile

将编译好的dll加载到powershell中:

$fileStream = ([System.IO.FileInfo] (Get-Item ".\$dllName")).OpenRead()
$dllBytes = new-object byte[] $fileStream.Length
$fileStream.Read($dllBytes, 0, $fileStream.Length)
$fileStream.Close()

[System.Reflection.Assembly]::Load($dllBytes)

在powershell中实例化代理客户端:

# Load System.ServiceModel, which can be found in your Framework\v3.0\Windows Communication Foundation folder
[System.Reflection.Assembly]::LoadFile($pathToSystemServiceModel)

# className is the name of your service
$serviceClientName = $className + "Client"

$basicHttpBinding = New-Object System.ServiceModel.BasicHttpBinding
$basicHttpBinding.MessageEncoding = [System.ServiceModel.WSMessageEncoding]::Mtom

$endPoint = New-Object System.ServiceModel.EndpointAddress($svcUri)
$wsClient = New-Object $serviceClientname($basicHttpBinding, $endPoint)

【讨论】:

@Kiquenet,这取决于您的服务公开的内容。在不恢复引发这一切的项目的情况下,我可以告诉你这样的调用的一个例子是:$wsClient.Foo()$wsClient.getItem($itemId)。我认为您甚至可以在您的$wsClient 上运行Get-Member cmdlet 来枚举其成员/方法:$wsClient | Get-Member 发现成员/方法使用Get-Member @Kiquenet ,您是否出于某种原因使Discover 这个词更加大胆?为了确保我们在同一页面上,我明确选择了枚举这个词来传达相同的想法。【参考方案2】:

我遇到了类似的问题。但是我碰巧已经将 ClientBase 生成的代码编译到本地程序集中。

我的解决方案是:

add-type -path "..\..\bin\MYassemblyWithWCFCLient.dll"
$binding = new-object system.servicemodel.basichttpbinding
$binding.MessageEncoding = "Mtom"
$endpoint = new-object System.ServiceModel.EndpointAddress("http://whodunit.oops/mtomandjerry.svc")
$regProxy = new-object MySpecialNamespace.OopsServiceContractClient($binding, $endpoint)

【讨论】:

以上是关于Powershell:使用 MTOM 消息编码使用 WCF 服务时出错的主要内容,如果未能解决你的问题,请参考以下文章

Python 发送 mtom 消息

WCF编解码实现

如何更改 powershell 终端颜色或完全关闭颜色编码

WCF系列 - WCF安全系列 - basicHttpBinding

使用基于MTOM的WSDL文件进行测试

使用 JAX-WS 和 MTOM/XOP 重写“Content-Type”标头和 MIME 边界