c# WebService SOAP及Rest調用

SOAP及Rest的調用區別參照以下:數據庫

REST彷佛在一晚上間興起了,這可能引發一些爭議,反對者能夠說REST是WEB誕生之始甚而是HTTP出現之日就相伴而生的原則。可是毋庸置疑的事實是,在Google和Yahoo等網絡巨頭髮布的相同功能的Web Service API中,REST無疑受到更多的青睞,所以是否是能夠這樣說:RPC在一晚上之間衰落了?

在一篇做業的小文章裏討論整套RPC的原理,無疑太過龐大了,何況RPC在Web Service領域的應用也無過XML-RPC以及由此延伸的SOAP而已。在原理上惟一重要的,是傳統程序的函數調用和返回在RPC中被請求和應答代替了而已。既然如此,在討論REST以前先闡述SOAP,多是合乎邏輯的順序。


什麼是SOAP?

SOAP (Simple Object Access Protocol) 顧名思義,是一個嚴格定義的信息交換協議,用於在Web Service中把遠程調用和返回封裝成機器可讀的格式化數據。事實上SOAP數據使用XML數據格式,定義了一整套複雜的標籤,以描述調用的遠程過程、參數、返回值和出錯信息等等。並且隨着須要的增加,又不得增長協議以支持安全性,這使SOAP變得異常龐大,背離了簡單的初衷。另外一方面,各個服務器均可以基於這個協議推出本身的API,即便它們提供的服務及其類似,定義的API也不盡相同,這又致使了WSDL的誕生。WSDL (Web Service Description Language) 也遵循XML格式,用來描述哪一個服務器提供什麼服務,怎樣找到它,以及該服務使用怎樣的接口規範,簡言之,服務發現。如今,使用Web Service的過程變成,得到該服務的WSDL描述,根據WSDL構造一條格式化的SOAP請求發送給服務器,而後接收一條一樣SOAP格式的應答,最後根據先前的WSDL解碼數據。絕大多數狀況下,請求和應答使用HTTP協議傳輸,那麼發送請求就使用HTTP的POST方法。


什麼是REST?

REST (REpresentational State Transfort) 形式上應該表述爲客戶端經過申請資源來實現狀態的轉換,在這個角度系統能夠當作一臺虛擬的狀態機。拋開R. T. Fielding博士論文裏晦澀的理論不說,REST應該知足這樣的特色:1)客戶端和服務器結構;2)鏈接協議具備無狀態性;3)可以利用Cache機制增進性能;4)層次化的系統;5)按需代碼。說到底,REST只是一種架構風格,而不是協議或標準。但這種新的風格(也許已經歷史悠久?)對現有的以SOAP爲表明的Web Service形成的衝擊也是革命性的,由於它面向資源,甚至連服務也抽象成資源,由於它和HTTP緊密結合,由於它服務器無狀態。


REST與SOAP的區別

由於SOAP並不假定傳輸數據的下層協議,所以必須設計爲能在各類協議上運行。即便絕大多數SOAP是運行在HTTP上,使用URI標識服務,SOAP也僅僅使用POST方法發送請求,用一個惟一的URI標識服務的入口。舉一個圖書館在線查詢管理系統爲例,服務提供者必須爲每一本書提供一個內部標識,而後可能定義一個listBooks操做來返回一系列圖書,一個getBook操做來返回指定的圖書,一個createBook操做來向數據庫加入新增的圖書,一個deleteBook操做來刪除做廢的圖書,每一個操做都有各自的參數,尤爲是用內部標識來標識操做的圖書。這種設計被詬病之處,在於deleteBook操做也要用POST方法來發送,而其實HTTP協議有更和邏輯的DELETE方法可用。REST正是這樣設計的,REST爲每個資源(此處是圖書)指定一個惟一的URI,而用HTTP的4種方法GET、POST、PUT、DELETE直觀地表示獲取、建立、更新和刪除圖書。同時圖書集合也是和單本的圖書不一樣的資源,若是用/books來表明圖書列表,/books/ID來表明標識爲ID的圖書,那麼對/books的GET操做就表明返回整個圖書列表,對/books/ID的DELETE操做表明刪除指定的圖書,等等。


REST的優勢

REST簡單而直觀,把HTTP協議利用到了極限,在這種思想指導下,它甚至用HTTP請求的頭信息來指明資源的表示形式(若是一個資源有多種形式的話,例如人類友善的頁面仍是機器可讀的數據?),用HTTP的錯誤機制來返回訪問資源的錯誤。由此帶來的直接好處是構建的成本減小了,例如用URI定位每個資源能夠利用通用成熟的技術,而不用再在服務器端開發一套資源訪問機制。又如只需簡單配置服務器就能規定資源的訪問權限,例如經過禁止非GET訪問把資源設成只讀。

服務器無狀態帶來了更多額外好處,由於每次請求都包含響應須要的全部信息,全部狀態信息都存儲在客戶端,服務器的內存從龐大的狀態信息中解放出來。並且如今即便一臺服務器忽然死機對客戶的影響也微乎其微,由於另外一臺服務器能夠立刻代替它的位置,而不須要考慮恢復狀態信息。更多的緩存也變成可能,而以前因爲服務器有狀態,對同一個URI的請求可能致使徹底不一樣的響應。整體結果是,網絡的容錯性和延展性都加強了,這些原本是WEB設計的初衷,日趨複雜和定製的WEB把它們破壞了,如今REST又返璞歸真,試圖把Web Service帶回簡單的原則中來。


REST是萬能的嗎?

可是REST就是萬能的嗎?無狀態帶來了巨大的優點,同時也帶來了難以解決的問題,例如,怎樣受權特定用戶才能使用的服務?怎樣驗證用戶身份?若是堅持服務器無狀態,也就是不記錄用戶登陸狀態,勢必要求每一次服務請求都包含完整的用戶身份和驗證信息。在這種狀況下,怎樣避免冒認?怎樣避免用戶信息泄漏?事實上,構建REST附屬的安全機制已經在討論中,其結果無非致使另外一個SOAP:複雜的需求摧殘了易用性。

REST的支持者聲稱REST的請求和應答數據簡單可讀,而SOAP則須要一系列繁瑣的封裝;即便如此,SOAP仍然不能達到接口的一致性,不一樣的廠商有各自的接口,而REST只使用HTTP定義的方法,所以是通用的。事實確實如此嗎?試想用REST實現兩數求和的服務,若是按照建議的作法,把服務(此處是加法)做爲一個資源,參數(此處是兩個加數)做爲請求的參數,結果以XML或JSON語法返回,是否比SOAP更簡單易用?通用接口仍然無法達到,由於資源的名稱、參數的名稱、結果的格式仍然是服務提供者定義的。爲了解決這個問題,提出了WASL(Web Application Description Language)來描述REST接口。WADL就像是WSDL的REST版,隨着REST被應用到複雜的領域,SOAP的影子無處不在。


面向資源和麪向事務

REST在面向資源的應用中左右逢源,但在面向事務的應用中卻未如人意。面向資源的應用操做簡單,無非建立、讀取、改變、刪除幾項,可是面向事務的應用不容許用戶直接操做資源,用戶只需向系統提交一個事務說明要求,而後等待事務的完成,就如一個網上銀行的用戶不直接修改帳戶和存款,而是提交一個事務告訴銀行本身要轉帳。若是把這樣的服務當作一種資源,經過向資源發送POST請求完成事務,那不過是SOAP的翻版而已,不管是這樣,仍是經過PUT來建立事務,都改變了系統的狀態(資源自己未改變,此處是改變了用戶的餘額),顯然違背了REST直觀的初衷。

事實上,一些Web Service提供者提供的REST API只有REST的外殼,傳輸的請求和應答全然是簡化了的SOAP,這種新瓶裝舊酒的作法只是加深了標準的分歧而已。歸根結底REST沒法簡單地解決一些應用,所以咱們只能看到SOAP在REST外殼下的借屍還魂。沒有一項技術能一勞永逸地解決全部問題,只須要在預約的約束下優美地解決所在領域的問題就足夠了。一項新技術推出的時候老是引來無數的跟風和吹捧,只有當塵埃落定以後才能獲得中肯的評價。

 

建立服務http://localhost:15383/WebService1.asmx,以下:json

/// <summary>
/// WebService1 的摘要說明
/// </summary>
//SOAP1.1調用時的SOAPAction=namespace+methodName
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 好比頭部文件Content-Type爲"application/json"時,需取消下列註釋
// 若要容許使用 ASP.NET AJAX 從腳本中調用此 Web 服務,請取消註釋如下行。 
// [System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{

    [WebMethod]
    public string HelloWorld(My my1, My my2)
    {
        return my1.Name + " " + my1.Value + "  " + my2.Name + " " + my2.Value;
    }

    [WebMethod]
    public string MyHello(string myname, string name)
    {
        return myname + name;
    }
}

public class My
{
    public string Name { get; set; }

    public string Value { get; set; }
}

SOAP1.1 與 SOAP1.2 區別:c#

SOAP 1.2 uses 「application/soap+xml」 as Content-Type and SOAP 1.1 uses 「text/xml」.
SOAP 1.2 does not use SOAPAction header line.
SOAP 1.2 uses 「http://www.w3.org/2003/05/soap-envelope」 as the envolope namespace and SOAP 1.1 uses 「http://schemas.xmlsoap.org/soap/envelope/

 

WebService服務的具體調用都可參照服務提供的說明。緩存

 

1、使用SOAP1.1調用示例,以HelloWorld爲例:安全

------頭部信息--------
POST /WebService1.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/HelloWorld"

------Body信息--------
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <HelloWorld xmlns="http://tempuri.org/">
      <my1>
        <Name>string</Name>
        <Value>string</Value>
      </my1>
      <my2>
        <Name>string</Name>
        <Value>string</Value>
      </my2>
    </HelloWorld>
  </soap:Body>
</soap:Envelope>


------響應信息--------
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <HelloWorldResponse xmlns="http://tempuri.org/">
      <HelloWorldResult>string</HelloWorldResult>
    </HelloWorldResponse>
  </soap:Body>
</soap:Envelope>

 

2、使用SOAP1.2調用示例,以HelloWorld爲例:服務器

--------頭部信息---------
POST /WebService1.asmx HTTP/1.1
Host: localhost
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

--------Body信息---------
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <HelloWorld xmlns="http://tempuri.org/">
      <my1>
        <Name>string</Name>
        <Value>string</Value>
      </my1>
      <my2>
        <Name>string</Name>
        <Value>string</Value>
      </my2>
    </HelloWorld>
  </soap12:Body>
</soap12:Envelope>


--------響應信息---------
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <HelloWorldResponse xmlns="http://tempuri.org/">
      <HelloWorldResult>string</HelloWorldResult>
    </HelloWorldResponse>
  </soap12:Body>
</soap12:Envelope>

c#調用示例以下:網絡

string str = "";
str += "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
str += "<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">";
str += "  <soap12:Body>                                                                                                                                                                  ";
str += "    <HelloWorld xmlns=\"http://tempuri.org/\">                                                                                                                                   ";
str += "      <my1>                                                                                                                                                                      ";
str += "        <Name>string</Name>                                                                                                                                                      ";
str += "        <Value>string</Value>                                                                                                                                                    ";
str += "      </my1>                                                                                                                                                                     ";
str += "      <my2>                                                                                                                                                                      ";
str += "        <Name>string</Name>                                                                                                                                                      ";
str += "        <Value>string</Value>                                                                                                                                                    ";
str += "      </my2>                                                                                                                                                                     ";
str += "    </HelloWorld>                                                                                                                                                                ";
str += "  </soap12:Body>";
str += "</soap12:Envelope>";

WebRequest request = HttpWebRequest.Create("http://localhost:15383/WebService1.asmx");
byte[] bs = Encoding.UTF8.GetBytes(str);
request.Method = "POST";
request.Timeout = 6000;
//SOAP1.1調用時需加上頭部信息request.Headers.Add("SOAPAction", "http://tempuri.org/HelloWorld");
request.ContentType = "application/soap+xml; charset=UTF-8";
request.ContentLength = bs.Length;
using (Stream reqStream = request.GetRequestStream())
{
    reqStream.Write(bs, 0, bs.Length);
    reqStream.Close();
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
    XmlDocument doc = new XmlDocument();
    StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
    String retXml = sr.ReadToEnd();
    sr.Close();
    doc.LoadXml(retXml);
    XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
    //此處是soap1.2,若是是soap1.1就應該以下:mgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
    mgr.AddNamespace("soap12", "http://www.w3.org/2003/05/soap-envelope");
    //解析XML
    var xmlNode = doc.SelectSingleNode("//soap12:Body/*", mgr);
    Console.WriteLine(xmlNode.FirstChild.InnerText);
}

Console.ReadKey();

 

3.使用HttpPost方式:架構

簡單參數(不是對象),好比MyHello方法,依照以下,也可使用HttpGet方式:app

------請求信息--------
POST /WebService1.asmx/MyHello HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: length

myname=string&name=string

------響應信息--------
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">string</string>

若是是使用複雜對象,上述方式便不能正常工做,能夠在WebService上加上[System.Web.Script.Services.ScriptService],使用json的數據傳輸方式調用,以下:函數

相關文章
相關標籤/搜索