這兩天在寫基於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格式對象的方式傳遞,例如:
複製代碼 代碼如下:
{"loginName":"name","password":"pwd"}
這裡要強調的是索引值對中,鍵必須加雙引號,且大小寫必須與服務方法中的形參定義完全一樣。
2)以json格式對象字串的形式傳遞,具體如下:
POST方式傳值
A)傳入非對象參數:
複製代碼 代碼如下:
{"loginName":"name","password":"pwd"}'
這裡要強調的是索引值對中,鍵必須加雙引號,且大小寫必須與服務方法中的形參定義完全一樣,值應按如下規則設定:字串加雙引號。
B)傳入對象參數:
複製代碼 代碼如下:
var person = {};
person.LoginName = $("#loginName").val();
person.Password = $("#password").val();
var jsonPerson = '{"person":' + $.toJSON(person) + '}';
這裡要強調的是對象屬性名稱的大小寫必須與資料類的屬性定義完全一致。
GET方式傳值
A)傳入非對象參數:
複製代碼 代碼如下:
'loginname="name"'
B)傳入對象參數:
複製代碼 代碼如下:
var person = {};
person.LoginName = $("#loginName").val();
person.Password = $("#password").val();
var jsonPerson = 'person=' + $.toJSON(person);
最後,說說WCF調試。
1、建議首先通過訪問http://localhost/wcf/personservice.svc的形式確認伺服器端部署成功,再進行用戶端和伺服器端聯調。
2、若需要代碼從用戶端運行開始直到伺服器端運行進行聯調,則必須使用同步調用,因此,使用jQuery的ajax時,必須將async設定為false。