天天看点

asp.net ajax学习笔记:客户端访问WebService

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方式传递

  • 在客户端和服务段传递对象时自动进行(JSon)序列化与反序列化。
  • 生成复杂对象代理时,需要在服务端使用GenerateScriptType属性标记要代理的类[GenerateScriptType(typeof(Color))]注:此标记可以标记在类、接口以及方法上
  • 如 果服务器端类型有基类、派生类等继承关系,当然可以根据具体的情况生成具体的派生类对象,还可以直接实例化一个Object对象,设置这个对象 __type属性,在把这个对象传递到服务端时,服务端可根据此标记自动反序列化为一个派生类,这样可以实现一个多态的效果,这个Object对象就是基 类的对象,根据__type属性自动实例化一个派生类(__type指定了传递负责对象对应的类型名称)

使用技巧:

存在派生类时:

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   謝謝作者。