這兩天在寫基於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。