這兩天在寫基於WCF服務的後台框架,過程中遇到了一些挫折,經過努力全部解決了,在此分享給大家,使用的工具是Visual Studio 2013。
此後台需要支援透過json來傳遞和接收資料。
首先,說說搭建過程。
第一步:建立WCF服務應用程式專案WCF。
第二步,建立服務使用的資料類別
using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.Serialization; namespace WCF { [DataContract] [Table("TUser")] public class Person { [DataMember] public int ID { get; set; } [DataMember] [StringLength(100)] public string LoginName { get; set; } [DataMember] [StringLength(100)] public string Password { get; set; } [DataMember] [DataType(DataType.Date)] public DateTime CreateDate { get; set; } } }
這裡,由於我使用EF來與資料庫交互,所以使用了Table、StringLength、DataType。若不使用EF,可以不加這些。 DataContract是用來標誌目前類別在序列化時需要參考DataMember屬性,若不設DataContract或僅設定DataMember,則所有共有屬性和欄位全部序列化,否則,只對設定有DataMember的序列化。請注意,DataContract和DataMember與反序列化無關,也就是說,當把一個json物件字串傳遞給WCF服務時,不管該欄位上是否有DataMember,都會被反序列化。
第三步:建立服務契約介面
如果你的服務只是用來提供Ajax等一些非WCF客戶端存取的,那麼是不需要介面的,把介面定義中的各種Attribute直接加在服務提供的類別的定義上即可。但是為了能讓程式可以透過服務介面來存取,那麼就必須使用接口,例如:前端MVC 後台WCF的架構形式。
using System.Collections.Generic; using System.ServiceModel; using System.ServiceModel.Web; namespace WCF { [ServiceContract] public interface IPersonService { [OperationContract] [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] Person CreatePerson(string loginName, string password); //服务功能2 [OperationContract] [WebGet(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] bool CheckMan(string loginName); } }
第四步,建立基於契約介面提供實際服務的類別
由於我的服務需要支援Ajax,所以選擇「WCF服務(支援Ajax)」一項,具體代碼如下:
using System; using System.Collections.Generic; using System.ServiceModel.Activation; namespace WCF { [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class PersonService : IPersonService { public Person CreatePerson(string loginName, string password) { return new PersonBLL().CreatePerson(loginName,password); } public bool CheckMan(string loginName) { return new PersonBLL().CheckMan(loginName); } } }
上述的PersonBLL是用來實際處理資料的業務邏輯層,有興趣的夥伴們可以自己寫個簡單的實作。
第五步,建立網頁客戶端。
在此為了避免處理跨網域問題,故把網頁post_get_test.html放在WCF專案下。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="jquery-1.10.2.js"></script> <script type="text/javascript" src="jqueryjson.js"></script> <title></title> </head> <body> <p> <input id="createPerson" type="button" value="POST_CreatePerson" /><br> <input id="checkMan" type="button" value="GET_CheckMan" /><br> <input type="text" id="loginName" /> <input type="text" id="password" /> </p> <script type="text/javascript"> $(document).ready(function () { $('#createPerson').click(function () { $.ajax({ type: "post", url: "personservice.svc/CreatePerson", data: '{"loginName":"' + $("#loginName").val() + '","password":"' + $("#password").val() + '"}', contentType: "application/json; charset=utf-8", dataType: "json", success: function (data) { alert("ID:" + data.d.ID + " Name:" + data.d.LoginName + " Password:" + data.d.Password + " CreateDate:" + data.d.CreateDate); }, error: function (xhr) { alert(xhr.responseText); } }); }); $('#checkMan').click(function () { $.getJSON("PersonService.svc/CheckMan", 'loginname="' + $("#loginName").val() + '"', function (data) { alert(data.d); }); }); }); </script> </body> </html>
建議在開發過程中採納createPerson按鈕呼叫方式來寫,其可以透過error回呼函數來回饋實際出錯原因,方便調試。
第六步,發佈WCF服務
右鍵WCF項目選擇“發布”選單項,在彈出視窗中的下拉清單中選擇“新設定檔”,輸入設定檔名稱,點選「確定」按鈕後進入連線設定介面,如下:
'
我是發佈在本機的IIS中,故選擇Web Deply發布方法,同時,這裡建議伺服器和網站名稱設定成:localhost和default web site/XXX,這裡XXX可以由你自己定義個服務網站的名字(實際上是IIS預設網站的虛擬目錄名稱),這樣,你的開發夥伴取得到該專案原始碼後,能發佈到完全相同的環境中,避免由於環境的差異延伸出一系列問題。
設定完畢後,點選“驗證連線”,出現綠色的鉤鉤,說明設定正確,點選“發佈”即可。
第七步,實測
1、現在可以透過瀏覽器存取http://localhost/wcf/personservice.svc來確認伺服器端是否部署成功,出現以下介面說明部署成功。
2、透過瀏覽器存取測試網頁http://localhost/wcf/post_get_test.html來檢查功能是否OK。
其次,以下說說我在搭建過程中出現的各種問題。
1、網頁透過Ajax呼叫服務的CreatePerson方法時把方法型別寫錯了,POST寫成了GET,結果係統報:405 (Method Not Allowed)。另外,根據微軟官網中描述,若透過soap存取一個WCF WEB HTTP應用程式(使用 WebHttpBinding 和 WebHttpBehavior 的服務)也會出現405錯誤。
2、web.config檔中endpoint節點的contract屬性設定錯誤,沒有指向WCF.IPersonService,網頁執行時報:500 (System.ServiceModel.ServiceActivationException);在使用http://localhost/wcf/ personservice.svc檢驗伺服器端部署結果時,封包:在服務「PersonService」實作的協定清單中找不到協定名稱「VME.Contract.PersonService」。
這裡需要說明的是若你的服務不是基於介面的,則endpoint的contract直接指向服務類別即可。
3、在使用jQuery的ajax並以POST方式傳送值給伺服器時,由於格式錯誤,報如下錯誤:500 (Internal Server Error),詳細資訊為:格式化程式嘗試對訊息進行反序列化時引發異常。正確的有兩種處理方式:
1)以json格式物件的方式傳遞,例如:
這裡要強調的是鍵值對中,鍵必須加雙引號,且大小寫必須與服務方法中的形參定義完全一樣。
2)以json格式物件字串的形式傳遞,具體如下:
POST方式傳值
A)傳入非物件參數:
這裡要強調的是鍵值對中,鍵必須加雙引號,且大小寫必須與服務方法中的形參定義完全一樣,值應按如下規則設定:字串加雙引號。
B)傳入物件參數:
這裡要強調的是物件屬性名稱的大小寫必須與資料類別的屬性定義完全一致。
GET方式傳值
A)傳入非物件參數:
B)傳入物件參數:
最後,說說WCF調試。
1、建議先透過存取http://localhost/wcf/personservice.svc的形式確認伺服器端部署成功,再進行客戶端和伺服器端聯調。
2、若需要程式碼從客戶端運行開始直到伺服器端運行進行聯調,則必須使用同步調用,因此,使用jQuery的ajax時,必須將async設為false。