什麼是 REST
REST (Representational State Transfer, 表徵狀態轉移)
REST 是一種軟體架構風格,希望網路上資源都可以用 URL 來指定,讓客戶端可以直接透過 URL 對資源進行 CRUD (創建、獲取、修改、刪除)操作。 RE 是 Representational 的縮寫,它代表由 Client 端透過 URI 取得的資源的具體象徵 (Representational), 應用程式可以依據取得的具體象徵來轉變其狀態(在瀏覽器上就是畫面的變化), 這樣不斷的反覆過程就是所謂的 Representational State Transfer。 維基百科:REST
JSON (Javascript Object Notation)
JSON 是一種以純文字為基礎的資料格式。它也是 REST 服務預設的訊息回應格式。 因為它的結構簡單,很適合用來做為程式溝通或交換資料時使用。 也由於它的輕量化和易於閱讀的特性,目前已廣泛應用於各種技術領域,例如:AJAX, WCF, jQuery。
你可以透過特定的格式去儲存任何資料(字串,數字,陣列,物件),也可以透過物件或陣列來傳送較複雜的資料。 底下是一個簡單的 JSON 範例:
{ "proudctName": "Computer Monitor", "price": "229.00", "specifications": { "size": 22, "type": "LCD", "colors": ["black", "red", "white"] } }
建立 REST WCF Service
用來建置 Windows Communication Foundation (WCF) 服務與用戶端應用程式時所需的型別,都包含在 System.ServiceModel 命名空間。 底下幾個相關的命名空間:
- System.ServiceModel : 提供與服務模型相關的類別。
- System.ServiceModel.Activation : 提供與服務模型啟動相關的類別。
- System.ServiceModel.Web : 提供使用 web 服務模型與相關的類別。
要設計 REST 服務,必須引用 System.ServiceModel.Web 命名空間。
該命名空間定義在 System.ServiceModel.Web.dll 組件裡,必須手動加入參考。
必須注意的是,Framework 版本必須選用完整版(如3.5或4.0 full profile),若選用 client profile 會找不到這個 dll。
建立支援 REST 的 WCF 服務
由於.NET 3.5 的支援,我們可以透過相當簡單的方式來建立 REST 的 WCF 服務,若開發人員想透過WCF技術,來開發 RESTful 的 Service,只需要在VS2008 SP1的專案範本中,選擇 「AJAX-enabled WCF Service」 即可:
「AJAX-enabled WCF Service」項目的內容
底下是一個 「AJAX-enabled WCF Service」的簡單範例,當新增一個 「AJAX-enabled WCF Service」項目時,下面幾點注意事項:
- 會自動加入 AspNetCompatibilityRequirements 屬性。
若設定成允許 ASP.NET相容性模式,則 WCF 服務會與 ASP.NET 使用相同的管線,類似於 ASMX 服務的方式。 在此模式下, WCF 服務也可提供 ASP.NET 檔案授權、 UrlAuthorization 和 HTTP 工作階段狀態等功能。 - 預設的 ResponseFormat 為 WebMessageFormat.Json 。
若要傳回 XML ,必須加入 [WebGet(ResponseFormat=WebMessageFormat.Xml)] 屬性宣告。 - WebInvoke :這屬性可用來設定 HTTP 動詞(例如:POST, PUT, DELETE),預設使用 HTTP POST 方式叫用。
- WebGet :這屬性是用來設定使用 HTTP GET 叫用。這種方法的回傳結果支援快取。
- 在第3行的 Namespace 中要設定一個值。
namespace WcfService2 { [ServiceContract(Namespace = "WcfService2")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class HRService { //一個方法若沒有特別宣告屬性,預設值有: //1. 必須使用 HTTP POST 叫用 //2. 回傳 Json 格式 [OperationContract] public Employee Employee1(string EmpID) { Employee emp = new Employee() { EmployeeID = EmpID, FirstName = "vito", LastName = "shao", Age = 30 }; return emp; } [OperationContract] [WebGet] public Employee Employee1(string EmpID) { Employee emp = new Employee() { EmployeeID = EmpID, FirstName = "vito", LastName = "shao", Age = 30 }; return emp; } [OperationContract] [WebGet] public Employee Employee2(string EmpID) { Employee emp = new Employee() { EmployeeID = EmpID, FirstName = "vito", LastName = "shao", Age = 30 }; return emp; } } public class Employee { public string EmployeeID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } }
「AJAX-enabled WCF Service」項目的組態設定
在這個設定內容裡,與前一節中的 WCF 服務最大的不同在於:
- 端點行為中加入 enableWebScript 屬性。它表示這個 endpoint 是一個支援 JSON 資料格式的 RESTful 服務,因此可以透過 AJAX 直接叫用。
- 端點的繫結方式採用 webHttpBinding。它指出該服務必須透過 HTTP 呼叫,而不是透過 SOAP 呼叫。
<configuration> <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> <behaviors> <endpointBehaviors> <behavior name="WcfService2.HRServiceAspNetAjaxBehavior"> <enableWebScript /> </behavior> </endpointBehaviors> </behaviors> <services> <service name="WcfService2.HRService"> <endpoint address="" binding="webHttpBinding" contract="WcfService2.HRService" behaviorConfiguration="WcfService2.HRServiceAspNetAjaxBehavior"/> </service> </services> </system.serviceModel> </configuration>
叫用 REST WCF Service
透過 ASP.NET AJAX ScriptManager 叫用 REST WCF Service
不曉得為什麼,在 ScriptManager 底下叫用 WCF 服務,該服務合約的 namespace 屬性值就必須指定為類別的命名空間,才可以成功呼叫。
namespace WcfService2 { [ServiceContract(Namespace = "WcfService2")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class HRService { } }
其用戶端的叫用方法如下:
<head id="Head1" runat="server"> <script language="javascript" type="text/javascript"> function Button1_onclick() { var service = new WcfService2.HRService(); var resutl = service.GetEmployee('001', onSuccess, onFail, null); } function onSuccess(result) { alert(result.FirstName + ' ' + result.LastName); } function onFail(result) { alert(result); } </script> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="HRService.svc" /> </Services> </asp:ScriptManager> <input id="Button1" type="button" value="invoke .svc with ajax" onclick="return Button1_onclick()" /> </div> </form> </body>
透過 jQuery 叫用 REST WCF Service
很奇怪,若使用 jQuery 叫用,該服務合約就不用指定 namespace 屬性。
其用戶端的叫用方法如下:
<head id="Head1" runat="server"> <title></title> <script type="text/javascript" src="./Scripts/jquery-1.8.2.js"></script> <script language="javascript" type="text/javascript"> function btnAjax_Post_onclick() { jQuery.support.cors = true; var empid = $("#txtEmpID").val(); var data = '{"EmpID":"' + empid + '"}'; var uri = "http://localhost:30302/HRService.svc/Employee1"; $.ajax({ type: "POST", url: uri, dataType: "json", data: data, contentType: "application/json; charset=utf-8", success: OnSuccess, error: OnFail }); } function btnAjax_Get_onclick() { jQuery.support.cors = true; var empid = $("#txtEmpID").val(); var uri = "http://localhost:30302/HRService.svc/Employee2?EmpID=" + empid; $.ajax({ type: "GET", url: uri, dataType: "json", contentType: "application/json; charset=utf-8", success: OnSuccess, error: OnFail }); } function OnSuccess(result) { alert(result.d.EmployeeID + ' ' + result.d.FirstName + ' ' + result.d.LastName); } function OnFail(result) { alert('Service call failed: ' + result.status + '' + result.statusText); } </script> </head> <body> <form id="form1" runat="server"> <div> EmpID: <input id="txtEmpID" type="text" value="007" /><br /><br /> <input id="btnAjax_Post" type="button" value="invoke .svc with ajax post" onclick="return btnAjax_Post_onclick()"/><br /><br /> <input id="btnAjax_Get" type="button" value="invoke .svc with ajax get" onclick="return btnAjax_Get_onclick()" /><br /><br /> </div> </form> </body>
底下是幾個 jQuery 用來叫用服務的方法:
- jQuery.ajax :Perform an asynchronous HTTP (Ajax) request.
- jQuery.getJSON :Load JSON-encoded data from the server using a HTTP GET request.
- jQuery.post :Load data from the server using a HTTP POST request.
- jQuery.get :Load data from the server using a HTTP GET request.
jQuery.ajax( url [, settings] ) jQuery.getJSON( url [, data] [, success(data, textStatus, jqXHR)] ) //Returns: jqXHR jQuery.post( url [, data] [, success(data, textStatus, jqXHR)] [, dataType] ) //Returns: jqXHR jQuery.get( url [, data ] [, success(data, textStatus, jqXHR) ] [, dataType ] ) //Returns: jqXHR
要注意一點,在 jQuery 1.4X 以後,叫用 jQuery 執行方法時,預設就不允許 cross-site 。如果要執行跨網站的方法,必須加入以下程式碼:
jQuery.support.cors = true;
套用 UriTemplate 叫用 REST WCF Service
使用 webHttp 端點行為
要使用 UriTemplate 必須使用 <webHttp> 端點行為,而不是使用 <enableWebScript> 端點行為。
<configuration> <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> <behaviors> <endpointBehaviors> <behavior name="WcfService3.HRServiceAspNetAjaxBehavior"> <webHttp helpEnabled="true" /> </behavior> </endpointBehaviors> </behaviors> <services> <service name="WcfService3.HRService"> <endpoint address="" binding="webHttpBinding" contract="WcfService3.HRService" behaviorConfiguration="WcfService3.HRServiceAspNetAjaxBehavior"/> </service> </services> </system.serviceModel> </configuration>
定義 UriTemplate
UriTemplate 是指這一個 RESTful 服務的呼叫方式(嚴格說起來是描述該資源的Uri位置),是要以何種 Uri 來表達,透過這種方式建立出來的 WCF 服務,就直接支援了 REST 型態的遠端呼叫方式。 例如,上例中我們給定的『UriTemplate』是"HR/EmpId/{EmpID}",則這個資源可以透過底下的網址來取得:
http://localhost:30303/HRService.svc/HR/EmpId/001
namespace WcfService3 { [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class HRService { [OperationContract] [WebInvoke( Method = "POST", UriTemplate = "HR/EmpId/{EmpID}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] public Employee Employee1(string EmpID) { Employee emp = new Employee() { EmployeeID = EmpID+"post", FirstName = "vito", LastName = "shao", Age = 30 }; return emp; } [OperationContract] [WebGet( UriTemplate = "HR/EmpId/{EmpID}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] public Employee Employee2(string EmpID) { Employee emp = new Employee() { EmployeeID = EmpID + "get", FirstName = "vito", LastName = "shao", Age = 30 }; return emp; } } public class Employee { public string EmployeeID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } }
使用 jQuery 方法叫用服務
<script language="javascript" type="text/javascript"> function btnAjax_Post_onclick() { jQuery.support.cors = true; var empid = $("#txtEmpID").val(); var data = '{"EmpID":"' + empid + '"}'; var uri = "http://localhost:30303/HRService.svc/HR/EmpId/" + empid; $.ajax({ type: "POST", url: uri, dataType: "json", data: data, contentType: "application/json; charset=utf-8", success: OnSuccess, error: OnFail }); } function btnAjax_Get_onclick() { jQuery.support.cors = true; var empid = $("#txtEmpID").val(); var uri = "http://localhost:30303/HRService.svc/HR/EmpId/" + empid; $.ajax({ type: "GET", url: uri, dataType: "json", contentType: "application/json; charset=utf-8", success: OnSuccess, error: OnFail }); } function btnPost_onclick() { jQuery.support.cors = true; var empid = $("#txtEmpID").val(); var uri = "http://localhost:30303/HRService.svc/HR/EmpId/" + empid; $.post(uri, null, OnSuccess); } function btnGet_onclick() { jQuery.support.cors = true; var empid = $("#txtEmpID").val(); var uri = "http://localhost:30303/HRService.svc/HR/EmpId/" + empid; $.get(uri, null, OnSuccess); } function OnSuccess(result) { alert(result.EmployeeID + ' ' + result.FirstName + ' ' + result.LastName); } function OnFail(result) { alert('Service call failed: ' + result.status + '' + result.statusText); } </script>
沒有留言:
張貼留言