學習.NET的開發人員,在WCF的光芒照耀下,Web Service 似乎快要被人遺忘了。因為身邊做技術的人一開口就是WCF多么的牛逼!廢話不多,本人很久不寫博客,今天總結一下最近幾日遇到的幾個關於WebService 跨語言的調用問題。
1 WebService 簡介
Web Service也叫XML Web Service WebService是一種可以接收從Internet或者Intranet上的其它系統中傳遞過來的請求,輕量級的獨立的通訊技術。是:通過SOAP在Web上提供的軟件服務,使用WSDL文件進行說明,並通過UDDI進行注冊。
Web Service的簡介就說這么多,大家都懂的,網上的資料太多了,搞過Web Service編程的人員都知道它的優點,沒有搞過WS編程的人員也知道它的優點,這里不再累述。
參考文章: http://baike.baidu.com/view/837392.htm
2 SOAP 消息結構
要學習WebService 肯定要了解Soap協議,它是WebService的基礎。
SOAP(Simple Object Access Protocol)簡單對象訪問協議,它是基於XML的消息傳遞協議,可以讓軟件組件和基於服務的應用程序能夠使用標准的HTTP協議進行通信(SOAP是基於HTTP之上的)。
SOAP的消息文檔是一個XML格式的。相信大家都看到過:
SOAP主要是由4部分組成:
SOAP Envelope
這是XML的頂層元素,語法如下:
(1)元素名為Envelope,必須存在,且為根元素。
(2)該元素可以包含命名空間和生命額外的屬性。如果出現額外屬性,則必須使用命名空間修飾。
SOAP Header
Header應該是Envelope中的第一個子元素,為可選的,語法規則如下:
(1)元素名為Header,不是必須存在,但如果存在則必須是SOAP Envelope的第一個直接子元素。
(2)Header的所有直接子元素都是它的Item,每個Itemdoiu必須有命名空間修飾。
(3)Header的Item也可以包含下級子元素,但這些子元素不是Header的Item,而是具體Item的內容。
此外,SOAP encodingStyle屬性用於指定Header條目的編碼風格,mustUnderstand屬性和actor屬性用於指定如何處理Item和由誰來處理。如:
<ENV:Header>
<uniB2B:Priority MXLns:uniB2B="some-URI"
ENV:mustUnderstand="1">7</uniB2B:Priority>
</ENV:Header>
SOAP Body
SOAP Body元素提供一個簡單的用於消息的最終接收者交換信息的機制。其語法如下:
(1)元素名為Body,必須在SOAP消息中出現,同時必須是SOAP Envelope的直接子元素,若沒有Header,則Body必須是第一個直接子元素;若有Header,則Body必須緊跟Header元素存在。
(2)與Header類似,每個Body的Item都必須由命名空間修飾。此外,Body中有個SOAP Fault元素,用於指示調用錯誤信息。
( 3 ) Body 的 Item 下的子元素不是 Body 的 Item 了,而是 Item 的內容
SOAP Fault
用於在SOAP消息中傳輸錯誤及狀態信息。如果存在則必須是Body的一個Item,且Body中只能出現一次Fault。SOAP Fault元素有以下幾個子元素:
(1) faultcode 必須在SOAP Fault元素中出現
(2)faultstring 該元素是為那些錯誤代碼提供用戶可以讀懂的錯誤解釋,它不是為程序處理而設置的。
(3)faultactor 該元素描述在消息路徑中錯誤的引發者,它類似於SOAP actor屬性,不過它不是指示Header條目的接收者,而是指示錯誤源。
3 WebService 5種模式
請求響應模式
fire-and-forget模式
高級消息模式
增量解析和處理模式
緩存模式
4 WebService 自定義SoapHeader安全驗證
SOAP 標頭提供了一種方法,用於將數據傳遞到 XML Web services 方法或從 XML Web services 方法傳遞數據,條件是該數據不直接與 XML Web services 方法的主功能相關。例如,一個 XML Web services 可能包含若干個 XML Web services 方法,而每個方法都需要自定義的身份驗證方案。您不用將參數添加到每個需要自定義身份驗證方案的 XML Web services 方法,而可以將引用從 SoapHeader 派生的類的 SoapHeaderAttribute 應用於每個 XML Web services 方法。從 SoapHeader 派生的類的實現處理該自定義身份驗證方案。按照此方式,XML Web services 方法使用 SOAP 標頭來僅實現特定於它的功能並添加其他功能。
下面的列表概述接收和處理 SOAP 標頭的基本步驟:
創建一個從 SoapHeader 派生的類,表示傳入 SOAP 標頭的數據。
將一個成員添加到實現 XML Web services 的類或 XML Web services 客戶端代理類(它們屬於在第一步創建的類型)。
指定第二步中在 MemberName 屬性中創建的成員,將 SoapHeaderAttribute 應用於 XML Web services 方法或代理類中的對應方法。
在 XML Web services 方法或 XML Web services 客戶端代碼中訪問 MemberName 屬性,以處理在 SOAP 標頭中發送的數據。
驗證例子代碼:
(1)首先定義一個自定義SoapHeader
{
public int ID { get; set; }
public string Name { get; set; }
public string PassWord { get; set; }
}
(2) 在WebService暴露的方法中添加SoapHeader描述
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem( false)]
public class Info : System.Web.Services.WebService
{
public SoapUnknownHeader[] unknownHeaders;
public MyHeader MyHeader { get; set; }
[WebMethod]
[SoapHeader( " unknownHeaders ")]
public string HelloWorld()
{
Console.WriteLine( " ?>>>>>>>>>>>>>>>>>>>> ");
return " Hello World ";
}
[SoapHeader( " MyHeader ", Direction = SoapHeaderDirection.InOut)]
[WebMethod]
public string Audit()
{
Validate();
return " 這里是驗證 ";
}
// 驗證函數 自定義
private string Validate()
{
if (MyHeader != null)
{
if (MyHeader.Name == MyHeader.PassWord)
{
return " 驗證通過 ";
}
else
{
return " 驗證失敗 ";
}
}
return " 未傳遞消息頭 ";
}
}
這里重點看的是服務暴露出來的方法public string Audit()
在WebService中的類定義一個屬性 public MyHeader MyHeader { get; set; } 就是我們自定義的SOAPHeader,同時還要在Audit()方法上加上如下描述:
[SoapHeader("MyHeader", Direction = SoapHeaderDirection.InOut)]
如果客戶端傳遞了相應的SoapHeader就會使用此屬性來接收消息,主要特性描述中的參數要指向定義的屬性名。
(3)客戶端生存代理
客戶端生成代理大家都知道,工程--右鍵--添加Web引用即可,現在我們看看里面生成的代碼
MyHeader客戶端生成的代理類
代理類中生存對應的屬性,同時此類也是繼承了SoapHeader類。
[System.Web.Services.Protocols.SoapDocumentMethodAttribute( " http://tempuri.org/Audit ", RequestNamespace= " http://tempuri.org/ ", ResponseNamespace= " http://tempuri.org/ ", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string Audit() {
object[] results = this.Invoke( " Audit ", new object[ 0]);
return (( string)(results[ 0]));
}
}
(4)客戶端調用
MyService.MyHeader myHeader = new MyService.MyHeader();
myHeader.ID = 1;
myHeader.Name = " qingyuan ";
myHeader.PassWord = " qingyuan ";
info.MyHeaderValue = myHeader;
string content= info.Audit();
Response.Write(content);
5 異語言之間的調用
在我們的工作中,很多時候遇到這樣的問題,有人說Java不能調用.NET 寫WebService。對他們沒有撒謊,那WebService跨平台豈不是笑話,其實不是這樣的,這個時候我們真正應該研究的是SOAP的自己個組成部分,我們可以使用WSDL來查看他們的不同之處。
.NET生存的WSDL一部分
Java生存的WSDL一部分
這里是同一個SoapHeader生成的WSDL,仔細看看還是有區別的,在java中的缺少一個form元素。 缺少這個元素就導致.NET的序列化機制無法識別這個xml文件。那該怎么辦呢。
在.NET的自定義SoapHeader的屬性上添加如下描述
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified)]
6 .NET中獲取匿名SoapHeader 內容
很多時候,我們做事情就和孔雀開屏,當然這不是諷刺啊,題外話!我們喜歡強加一些自己的意願和想法在里面。
我存在一個WebService的服務端,現在客戶端調用這個WebService的時候強制提交了一個SOAPHeader報文,希望WebService能夠處理。上面一部分我們可以發現客戶端提交一個SOAPHeader的時候服務端有一個承載體,因為我們在服務端的時候就在暴露的方法中用SOAPHeader描述過了,現在就是服務端沒有使用自定義SOAPHeader描述,而客戶端強制提交了一個SOAPHeader,這樣我們怎么處理。
1. 客戶端定義一個SOAPHeader自定義對象
{
public MyInfo()
{
}
public int ID { get; set; }
public string Name { get; set; }
}
這里是在客戶端添加的SoapHeader ,不要在服務端添加此類
2. 客戶端代理方法添加SOAPHeader的描述
public MyInfo MyInfo { get; set; }
[SoapHeader( " MyInfo ", Direction = SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute( " http://tempuri.org/HelloWorld ", RequestNamespace= " http://tempuri.org/ ", ResponseNamespace= " http://tempuri.org/ ", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string HelloWorld() {
object[] results = this.Invoke( " HelloWorld ", new object[ 0]);
return (( string)(results[ 0]));
}
/*******************************************************************/
這里和普通的代理方式一樣,添加客戶端SOAPHeader的描述
3. 服務端添加匿名SOAPHeader的處理
[SoapHeader( " unknownHeaders ")]
public string HelloWorld()
{
Console.WriteLine( " ?>>>>>>>>>>>>>>>>>>>> ");
return " Hello World ";
}
服務端需要使用SoapUnknownHeader來接收匿名提交的SoapHeader。因為在服務端沒有對應的載體,而在暴露的方法上面也需要添加相應的描述
4. 客戶端調用
MyInfo myInfo = new MyInfo();
myInfo.ID = 1;
myInfo.Name = " dddd ";
info.MyInfo = myInfo;
string name = info.HelloWorld();
Response.Write(name);
啟動服務端的調試模式跟蹤一下看看提交的數據
從上圖可以看出,數據已經傳輸過來了,得到的是一個xml格式的數據,對於xml的解析在.NET中不是難事,在此就可以完成匿名SoapHeader報文的發送和接收
7 JavaScript 異步調用WebService
參考:http://www.cnblogs.com/qingyuan/archive/2009/12/09/1620405.html