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 border='1'>"); 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 { /**//// <summary> /// Summary description for CustomizeTypeResolver /// </summary> public class CustomizeTypeResolver : JavaScriptTypeResolver { //从字符串标识获取一个Type对象 public override Type ResolveType(string id) { //id就是从客户端对象的__type的值 switch (id) { case "0": return typeof(Intern); case "1": return typeof(Vendor); case "2": return typeof(FulltimeEmployee); } return null; } //得到Type对象的标识字符串 public override string ResolveTypeId(Type type) { if (type == typeof(Intern)) { //返回客户端就是__type属性的值 return "0"; } else if (type == typeof(Vendor)) { return "1"; } else if (type == typeof(FulltimeEmployee)) { return "2"; } return null; } } } 这是类的定义 Employee emp = null; switch (id) { case 0: emp = new Intern(); break; case 1: emp = new Vendor(); break; default: emp = new FulltimeEmployee(); break; } //用Resolver对象来实例一个JavaScriptSerializer对西那个 JavaScriptSerializer serializer = new JavaScriptSerializer(new CustomizeTypeResolver()); //序列化复杂对象 return serializer.Serialize(emp); 这是使用方法 7、改变客户端访问WebService代理方法名
使用Get方式访问WebService的方法,必须加上[ScriptMethod(UseHttpGet=true)]标记, 参数将使用QueryString进行传递,性能较HTTPPOST方法略有提高 9、让方法返回XML对象
10、在WebService方法中使用Session 在WebMethod标签中加入EnableSession=true参数11、在客户端调用WebService的安全性
Invoke方法签名 Sys.Net.WebServiceProxy.invoke= function ( servicePath,/*Service路径*/ methodName,/*方法名*/ useGet,/*是否使用HTTPGET方法*/ 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
謝謝作者。
|