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="<http://tempuri.org/0>";边界=“uuid: 4001d529-32b9-4560-9f4b-550c35c67b03+id=4";start-info="text/xml"',但预期为 'text/xml'。 请求失败并显示错误消息: -- --uuid:4001d529-32b9-4560-9f4b-550c35c67b03+id=4 内容 ID:<http://tempuri.org/0> 内容传输编码:8bit 内容类型:application/xop+xml;charset=utf-8;type="text/xml" <s:信封 xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:身体> <TestWebServiceConnectionResponse xmlns="http://myserver.com/"> <TestWebServiceConnectionResult>成功</TestWebServiceConnectionResult> </TestWebServiceConnectionResponse> </s:身体> </s:信封> --uuid:4001d529-32b9-4560-9f4b-550c35c67b03+id=4-- --。” 在 line:1 char:38 + $proxyObject.TestWebServiceConnection <<<< () >> error.txt + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodException
注意 我可以通过其他客户端甚至微软提供的 wcfclient 工具来使用 WCF 服务。您可以看到 TestWebServiceConnectionResult 返回了 success,但代理对象似乎无法解析响应。
行为:
<服务行为> <behavior name="MyServiceBehavior"> <serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100"/> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/> <serviceDebug includeExceptionDetailInFaults="false"/> </行为> </服务行为>
绑定(我已经排除了超时值/阅读器配额和消息大小,因为它们的值的排列似乎与我的问题无关):
<basicHttpBinding> <binding name="basicHttpEndpointBinding" messageEncoding="Mtom"> <security mode="无"> <transport clientCredentialType="None"/> </安全> </basicHttpBinding>
服务
<service behaviorConfiguration="MyServiceBehavior" name="MyService.AccessService"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" name="basicHttpEndpointAccessService" bindingNamespace="http://myserver.com/" contract="MyService.IAccessService"/> <endpoint address="mex" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" name="mexEndpointAccess" contract="IMetadataExchange"/> </服务>
【问题讨论】:
作为一个测试,你能不能把服务消息编码改为文本,看看它是否开始工作? (这将证明 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.exe
和 csc.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 服务时出错的主要内容,如果未能解决你的问题,请参考以下文章