天天看點

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