asp.net ajax學習筆記:用戶端通路WebService 2008年07月02日 星期三 下午 06:09
1、用戶端通路WebService,那麼WebService類必須加上[ScriptService]标記,此标記在 System.Web.Script.Services命名空間下,并且被通路的方法必須是public和加上[WebMethod]标記。用戶端在 ScriptManager标簽之間加上如下代碼 <Services> <asp:ServiceReference Path="命名空間/WebService.asmx" InlineScript="true" /> </Services> InlineScript屬性表示是否将代理緩存到頁面中(HTML源碼中)。 2、用戶端通路PageMethod,頁面的方法必須寫在aspx頁面檔案對應的aspx.cs檔案上。方法必須是public和 static并且用[WebMethod]标記。用戶端必須使用PageMethods.MethodName()通路,并且與通路WebService一樣有成功後的回調函數。注:ScriptManager的EnablePageMethods屬性必須設定為true,才能通路頁面的方法。 3、WebMethod(arg1, …, argN, onSucceeded, onFailed,userContext) 4、傳遞負責類型,複雜類型預設以JSON方式傳遞
使用技巧: 存在派生類時: namespace ComplexType { public abstract class Employee { private int _Years; public int Years { get { return this._Years; } set { this._Years = value; } } public string RealStatus { get { return this.GetType().Name; } } public abstract int CalculateSalary(); } public class Intern : Employee { public override int CalculateSalary() { return 2000; } } public class Vendor : Employee { public override int CalculateSalary() { return 5000 + 1000 * (Years - 1); } } public class FulltimeEmployee : Employee { public override int CalculateSalary() { return 15000 + 2000 * (Years - 1); } WebService要針對不再方法中傳遞的對象設定屬性: [WebMethod] [GenerateScriptType(typeof(Intern))] [GenerateScriptType(typeof(Vendor))] [GenerateScriptType(typeof(FulltimeEmployee))] public string CalculateSalary(Employee employee) { return "I'm " + employee.RealStatus + ", my salary is " + employee.CalculateSalary() + "."; } 用戶端使用技巧: <select id="comboStatus" style="width:150px;"> <option value="ComplexType.Intern">Intern</option> <option value="ComplexType.Vendor">Vendor</option> <option value="ComplexType.FulltimeEmployee">FTE</option> </select> ==================== function calculateSalary() { // var emp = null; // var combo = $get("comboStatus"); // // switch(combo.options[combo.selectedIndex].text) // { // case "Intern": // emp = new ComplexType.Intern(); // break; // case "Vendor": // emp = new ComplexType.Vendor(); // break; // case "FTE": // emp = new ComplexType.FulltimeEmployee(); // break; // } var emp = new Object(); emp.__type = $get("comboStatus").value; emp.Years = parseInt($get("txtYears").value, 10); EmployeeService.CalculateSalary(emp, onSucceeded); } 5、用JavaScriptConverter解決複雜對象由于循環引用的問題 使用DataTable這樣的複雜類型時,可以使用JavaScriptConverter來解決 引用Microsoft.Web.Preview.dll程式集,web.config做如下設定 <jsonSerialization> <converters> <add name="DataSetConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataSetConverter, Microsoft.Web.Preview" /> <add name="DataRowConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataRowConverter, Microsoft.Web.Preview" /> <add name="DataTableConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataTableConverter, Microsoft.Web.Preview" /> <add name="BoyConverter" type="Converter.BoyConverter, App_Code" /> </converters> </jsonSerialization> WebService代碼如下: [WebMethod] public DataTable GetDataTable() { DataTable dt = new DataTable(); dt.Columns.Add(new DataColumn("ID", typeof(int))); dt.Columns.Add(new DataColumn("Text", typeof(string))); Random random = new Random(DateTime.Now.Millisecond); for (int i = 0; i < 10; i++) { dt.Rows.Add(i, random.Next().ToString()); } return dt; } 用戶端可通過對象方式引用: function getDataTable() { DataTableService.GetDataTable(onSucceeded, onFailed); } function onSucceeded(result) { // alert(result); var sb = new Sys.StringBuilder("<table >"); sb.append("<tr><td>ID</td><td>Text</td></tr>"); for (var i = 0; i < result.rows.length; i++) { sb.append( String.format( "<tr><td>{0}</td><td>{1}</td></tr>", result.rows[i]["ID"], result.rows[i].Text)); } sb.append("</table>"); $get("result").innerHTML = sb.toString(); } function onFailed(error) { alert(error.get_message()); } 自己編寫JavaScriptConverter namespace Converter { public class BoyConverter : JavaScriptConverter { //此方法在由用戶端的對象向服務段對象進行傳遞時調用 public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { //執行個體化一個Boy對象 Boy boy = new Boy(); //将Boy的Name被設定為dictionary的Name的key的值 boy.Name = (string)dictionary["Name"]; //注意dictionary["GirlFriend"]的值是一個JSon對象,用來儲存用戶端GirlFriend的對象 //是以需要用JavaScriptSerializer來将此JSon對象轉換為一個服務段Gril對象 boy.GirlFriend = serializer.ConvertToType<Girl>(dictionary["GirlFriend"]); //設定boy的GirlFriend的BoyFirend,在服務端不用擔心循環引用的問題 boy.GirlFriend.BoyFriend = boy; //傳回被設定好的Boy對象 return boy; } //此方法在由服務端對象向用戶端對象進行傳遞是調用 public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { //轉換傳遞進來的參數為Boy類型 Boy boy = (Boy)obj; //執行個體化一個字典類型 IDictionary<string, object> result = new Dictionary<string, object>(); //設定字典類型的key為Name,值為Boy的Name result["Name"] = boy.Name; //将boy的GirFriend的BoyFriend引用設定為空,避免在用戶端出現循環引用的問題 boy.GirlFriend.BoyFriend = null; //設定字典類型的key為GirlFriend為Boy的GirlFriend result["GirlFriend"] = boy.GirlFriend; //傳回IDictionary對象,到用戶端被轉換為JSon對象,并且,不能使用boy.GirlFriend.BoyFriend //類似的代碼 return result; } public override IEnumerable<Type> SupportedTypes { get { //在 foreach 每次循環調用疊代程式的 //MoveNext 方法時,它都從前一次 yield return 語句停止的地方開始執行 yield return typeof(Boy); } } } 在實作好JavaScriptConverter類之後,需要在WebConfig裡加上指定的Converter标簽<add name="BoyConverter" type="Converter.BoyConverter, App_Code"/>加載的地方與DataTable類似。Name:轉換者的名字,随便起 Type:Converter.BoyConverter轉換者的命名空間加類名,App_Code:轉換者類檔案存放的位址,好像無所謂,我随便填也沒出錯 6、序列化和反序列化 * 用戶端的反序列化: Sys.Serialization.JavaScriptSerializer.deserialize('<%= this.SerializedDateTime %>'); * 服務端的序列化 JavaScriptSerializer serializer = new JavaScriptSerializer(); serializer.Serialize(DateTime.Now); 注意:用戶端是靜态方法。DateTime序列化後不是一個JSon字元串。 * 上面是簡單類型的序列化和反序列化,如果是複雜的對象類型需要用到JavaScriptTypeResolver 自定義一個Resolver類并繼承JavaScriptTypeResolver類,重寫ResolveType、ResolveTypeId兩個方法 JavaScriptTypeResolver不是一個直接使用的類,他是用來輔助JavaScriptSerializer類的,作為構造函數的參數傳入。 namespace TypeResolver { methodName, useGet, params, onSucceeded, onFailure, userContext, timeout ){ } function getRandom(minValue, maxValue) { Sys.Net.WebServiceProxy.invoke( "Services/UseHttpGetService.asmx", "GetRangeRandom", true, { "minValue" : minValue, "maxValue" : maxValue}, onSucceeded, null, null, -1); } 對應上面的invoke參數說明和例子,對WebService生成的代理方法是如何調用WebService有一定了解 **************************************************************************************************************************** 轉自: http://hi.baidu.com/freezesoul/blog/item/38bfb1115ef56c7bcb80c45e.html 謝謝作者。 |