http://www.cnblogs.com/zitjubiz/archive/2011/09/27/WCF_Soap_Header.html
最近Oracle的DRM系统发布了新版本,其中的webService发生了重大的转变. 把验证信息放在了SoapHeader里面.
这样原来系统(在vs.net2005开发).net引用WebService就不能成功调用了. 因为默认的代理类调用是没有SoapHeader的.
新版DRM的Soap信息如下:
<
soap:Envelope
xmlns:soap
="http://schemas.xmlsoap.org/soap/envelope/"
>
< soap:Header >
< wsse:Security soap:mustUnderstand ="1" xmlns:wsse ="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" >
< wsse:UsernameToken >
< wsse:Username >UserName </ wsse:Username >
< wsse:Password Type ="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" >Password </ wsse:Password >
</ wsse:UsernameToken >
</ wsse:Security >
< AppParameters xmlns ="http://drm.webservices.epm.oracle" >
< serverUrl >http://DRMServer:5240/Oracle/Drm/APIAdapter </ serverUrl >
< sessionParams >ProductVersion=11.1.2.1 </ sessionParams >
</ AppParameters >
</ soap:Header >
< soap:Body xmlns:ns1 ="http://drm.webservices.epm.oracle" >
< ns1:getVersions />
</ soap:Body >
</ soap:Envelope >
< soap:Header >
< wsse:Security soap:mustUnderstand ="1" xmlns:wsse ="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" >
< wsse:UsernameToken >
< wsse:Username >UserName </ wsse:Username >
< wsse:Password Type ="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" >Password </ wsse:Password >
</ wsse:UsernameToken >
</ wsse:Security >
< AppParameters xmlns ="http://drm.webservices.epm.oracle" >
< serverUrl >http://DRMServer:5240/Oracle/Drm/APIAdapter </ serverUrl >
< sessionParams >ProductVersion=11.1.2.1 </ sessionParams >
</ AppParameters >
</ soap:Header >
< soap:Body xmlns:ns1 ="http://drm.webservices.epm.oracle" >
< ns1:getVersions />
</ soap:Body >
</ soap:Envelope >
在园子里搜了一下, 找到下面的方法 .net 调用 Java编写的WebService
但他这个文章,每个方法都要一个xml,太啰嗦了,我改成传MethodName和Param进去之后,重写整个<soap:body>
修改后的关键代码如下:
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(
"
WinFormDRMService.SoapHeader.xml
");
xml = new XmlDocument();
xml.Load(stream);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
nsmgr.AddNamespace( " soap ", " http://schemas.xmlsoap.org/soap/envelope/ ");
XmlNode SoaoBodyNode = xml.SelectSingleNode( " soap:Envelope/soap:Body ", nsmgr);
string SoapBodyNodeInnerXml = " <ns1: " + MethodName + " > ";
// 修改参数的值
foreach (DictionaryEntry de in Pars)
{
Hashtable subpars = de.Value as Hashtable;
// 如果参数不是Hashtable,就直接用其key,value
if (subpars == null)
{
SoapBodyNodeInnerXml += " <ns1: " + de.Key.ToString() + " > ";
SoapBodyNodeInnerXml += de.Value.ToString()+ " </ns1: " + de.Key.ToString() + " > ";
}
else
{
SoapBodyNodeInnerXml += " <ns1: " + de.Key.ToString() + " > ";
foreach (DictionaryEntry subde in subpars)
{
SoapBodyNodeInnerXml += " <ns1: " + subde.Key.ToString() + " > ";
SoapBodyNodeInnerXml += subde.Value.ToString() + " </ns1: " + subde.Key.ToString() + " > ";
}
SoapBodyNodeInnerXml += de.Value.ToString() + " </ns1: " + de.Key.ToString() + " > ";
}
}
SoapBodyNodeInnerXml += " </ns1: " + MethodName + " > ";
SoaoBodyNode.InnerXml = SoapBodyNodeInnerXml;
// 将修改后的XML文件保存到流中
// 这样做还可以保证发送的XML文件也是格式化的那种形式,而不是一整行
// 如通过OuterXml获取的就是一整行,这样也可能会导致服务端解析失败,个人这次就碰到这种情况了
MemoryStream outStream = new MemoryStream();
xml.Save(outStream);
xml = new XmlDocument();
xml.Load(stream);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
nsmgr.AddNamespace( " soap ", " http://schemas.xmlsoap.org/soap/envelope/ ");
XmlNode SoaoBodyNode = xml.SelectSingleNode( " soap:Envelope/soap:Body ", nsmgr);
string SoapBodyNodeInnerXml = " <ns1: " + MethodName + " > ";
// 修改参数的值
foreach (DictionaryEntry de in Pars)
{
Hashtable subpars = de.Value as Hashtable;
// 如果参数不是Hashtable,就直接用其key,value
if (subpars == null)
{
SoapBodyNodeInnerXml += " <ns1: " + de.Key.ToString() + " > ";
SoapBodyNodeInnerXml += de.Value.ToString()+ " </ns1: " + de.Key.ToString() + " > ";
}
else
{
SoapBodyNodeInnerXml += " <ns1: " + de.Key.ToString() + " > ";
foreach (DictionaryEntry subde in subpars)
{
SoapBodyNodeInnerXml += " <ns1: " + subde.Key.ToString() + " > ";
SoapBodyNodeInnerXml += subde.Value.ToString() + " </ns1: " + subde.Key.ToString() + " > ";
}
SoapBodyNodeInnerXml += de.Value.ToString() + " </ns1: " + de.Key.ToString() + " > ";
}
}
SoapBodyNodeInnerXml += " </ns1: " + MethodName + " > ";
SoaoBodyNode.InnerXml = SoapBodyNodeInnerXml;
// 将修改后的XML文件保存到流中
// 这样做还可以保证发送的XML文件也是格式化的那种形式,而不是一整行
// 如通过OuterXml获取的就是一整行,这样也可能会导致服务端解析失败,个人这次就碰到这种情况了
MemoryStream outStream = new MemoryStream();
xml.Save(outStream);
该方法调用成功,但它有个缺点,只适用了类比较少,没什么复杂类型的WebService, 假如有上百个方法和自定义类, 你还要自己解析xml包装成类,又等于重新造轮子,而且99%可能性没有微软造的好.
待续 To be continue...
调用非.net系统的Webservice的探索 ( 三 ) -WCF
WCF的模型和之前.net的WS有所不同. 你在添加Service Reference生成的代理类可以看到
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute( " System.ServiceModel ", " 4.0.0.0 ")]
public partial class MathServiceClient : System.ServiceModel.ClientBase<IMathService>, IMathService {}
[System.CodeDom.Compiler.GeneratedCodeAttribute( " System.ServiceModel ", " 4.0.0.0 ")]
public partial class MathServiceClient : System.ServiceModel.ClientBase<IMathService>, IMathService {}
而WCF著名的"ABC"
而我们这里调用java系统的WebService,只需要处理Address和Binding
来看看生成的app.config内容,留意黄色高亮的,是我们手工添加修改的.
<
configuration
>
< system.serviceModel >
< bindings >
< customBinding >
< binding name ="IDrmServiceSoapHttp" >
< security authenticationMode ="UserNameOverTransport"
allowInsecureTransport ="true" includeTimestamp ="false" >
</ security >
< textMessageEncoding maxReadPoolSize ="64" maxWritePoolSize ="16"
messageVersion ="Soap11" writeEncoding ="utf-8" >
< readerQuotas maxDepth ="32" maxStringContentLength ="8192" maxArrayLength ="16384"
maxBytesPerRead ="4096" maxNameTableCharCount ="65536" />
</ textMessageEncoding >
< httpTransport manualAddressing ="false" maxBufferPoolSize ="524288"
maxReceivedMessageSize ="65536" allowCookies ="false" authenticationScheme ="Anonymous"
bypassProxyOnLocal ="false" decompressionEnabled ="true" hostNameComparisonMode ="StrongWildcard"
keepAliveEnabled ="true" maxBufferSize ="65536" proxyAuthenticationScheme ="Anonymous"
realm ="" transferMode ="Buffered" unsafeConnectionNtlmAuthentication ="false"
useDefaultWebProxy ="true" />
</ binding >
</ customBinding >
</ bindings >
< client >
< endpoint address ="http://localhost:8080/oracle-epm-drm-webservices/DrmService"
binding ="customBinding" bindingConfiguration ="IDrmServiceSoapHttp"
contract ="DRM.IDrmService" name ="DrmServicePortType" >
< headers >
< AppParameters xmlns ="http://drm.webservices.epm.oracle" >
< serverUrl > http://DRMServer:5240/Oracle/Drm/APIAdapter </ serverUrl >
< sessionParams > ProductVersion=11.1.2.1 </ sessionParams >
</ AppParameters >
</ headers >
</ endpoint >
</ client >
</ system.serviceModel >
</ configuration >
< system.serviceModel >
< bindings >
< customBinding >
< binding name ="IDrmServiceSoapHttp" >
< security authenticationMode ="UserNameOverTransport"
allowInsecureTransport ="true" includeTimestamp ="false" >
</ security >
< textMessageEncoding maxReadPoolSize ="64" maxWritePoolSize ="16"
messageVersion ="Soap11" writeEncoding ="utf-8" >
< readerQuotas maxDepth ="32" maxStringContentLength ="8192" maxArrayLength ="16384"
maxBytesPerRead ="4096" maxNameTableCharCount ="65536" />
</ textMessageEncoding >
< httpTransport manualAddressing ="false" maxBufferPoolSize ="524288"
maxReceivedMessageSize ="65536" allowCookies ="false" authenticationScheme ="Anonymous"
bypassProxyOnLocal ="false" decompressionEnabled ="true" hostNameComparisonMode ="StrongWildcard"
keepAliveEnabled ="true" maxBufferSize ="65536" proxyAuthenticationScheme ="Anonymous"
realm ="" transferMode ="Buffered" unsafeConnectionNtlmAuthentication ="false"
useDefaultWebProxy ="true" />
</ binding >
</ customBinding >
</ bindings >
< client >
< endpoint address ="http://localhost:8080/oracle-epm-drm-webservices/DrmService"
binding ="customBinding" bindingConfiguration ="IDrmServiceSoapHttp"
contract ="DRM.IDrmService" name ="DrmServicePortType" >
< headers >
< AppParameters xmlns ="http://drm.webservices.epm.oracle" >
< serverUrl > http://DRMServer:5240/Oracle/Drm/APIAdapter </ serverUrl >
< sessionParams > ProductVersion=11.1.2.1 </ sessionParams >
</ AppParameters >
</ headers >
</ endpoint >
</ client >
</ system.serviceModel >
</ configuration >
调用方法如下:
MathServiceClient svc =
new MathServiceClient();
svc.ClientCredentials.UserName.UserName = " MyUserName ";
svc.ClientCredentials.UserName.Password = " MyPassword ";
label1.Text =svc.Add( 1, 2);
svc.ClientCredentials.UserName.UserName = " MyUserName ";
svc.ClientCredentials.UserName.Password = " MyPassword ";
label1.Text =svc.Add( 1, 2);
WCF整个使用方法对比起WSE就简单很多了.
但作为客户端来说,我粗略测试了性能, 和WSE差不多,WCF还略慢一点.