之前在Ajax初步理解中介紹了對Ajax的初步理解,本文將介紹在ASP.NET中如何方便使用Ajax,第一種當然是使用jQuery的ajax,功能強大而且操作簡單方便,第二種是使用.NET封裝好的ScriptManager。
$.ajax向普通頁面發送get請求
這是最簡單的一種方式了,先簡單瞭解jQuery ajax的文法,最常用的調用方式是這樣:$.ajax({settings}); 有幾個常用的setting,全部參數及其解釋可以去jQuery官方API文檔查詢
1. type:請求方式 get/post
2. url:請求的Uri
3. async:請求是否為非同步
4. headers:自訂的header參數
5. data:發往伺服器的參數
6. dataType:參數格式,常見的有string、json、xml等
7. contents:決定怎樣解析response的一個”字串/Regex” map
8. contentType:發送到伺服器的額資料的內容編碼類別型,它的預設值是"application/x-www-form-urlencoded; charset=UTF-8""。
9. success:請求成功後調用的控制代碼
10.error:請求失敗後調用的控制代碼
沒使用過jQuery的ajax話這樣看有些雲裡霧裡的感覺,來看一個簡單例子
首先使用Visual Studio建立一個WebApplication,把jQuery.js引入project,然後添加兩個頁面,Default.aspx作為測試用
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Web.Default" %><!DOCTYPE html ><html><head runat="server"> <title>Ajax</title> <script src="jQuery.js" type="text/javascript"></script> <style type="text/css"> html, body, form { width: 100%; height: 100%; padding: 0px; margin: 0px; } #container { margin: 100px; height: 300px; width: 500px; background-color: #eee; border: dached 1px #0e0; } </style></head><body> <form id="form1" runat="server"> <div id="container"> <input type="button" value="Test Ajax" onclick="testGet()" /> <br /> </div> <script type="text/javascript"> function setContainer(text) { document.getElementById("container").innerHTML += ('<br/>' + text); } function testGet() { $.ajax({ type: 'get', url: 'NormalPage.aspx', async: true, success: function (result) { alert(result); }, error: function () { setContainer('ERROR!'); } }); } </script> </form></body></html>
NormalPage.aspx作為請求頁面,先不做任何處理。在Default.aspx頁面中的JavaScript中可以看到testGet函數就利用jQuery的ajax向Normal.aspx發送了了一個get請求,沒寫的參數使用jQuery預設參數,這個調用沒使用任何參數,簡單向Normal.aspx頁面發送請求,請求成功則alert全部response(即success方法參數:result,jQuery會把responseText傳入success方法第一個參數),請求失敗則向DIV中添加一行錯誤提示文本。如果一切正常,可以看到頁面彈出對話方塊,對話方塊內內容即是Normal.aspx頁面內容
一個簡單的get請求完成了,這樣的結果一般沒有多大用處,也不是ajax意圖所在,使用Ajax主要是想使用JavaScript可以非同步向伺服器發送特定請求,擷取伺服器相關資料,比如向伺服器詢問天氣,然後獲得天氣資料,更新頁面,而不是擷取整個頁面,換句話說,使用Ajax本身就是為了擺脫更新整個頁面來更新頁面資料這種模式,僅僅需要伺服器給我們資料即可,這就需要調用伺服器端的特定方法。
$.ajax GET請求調用伺服器特定方法
我們這時候需要修改NormalPage.aspx,為其添加幾個方法供Default.aspx測試調用
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;namespace Web{ public partial class NormalPage : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string action = Request.QueryString["action"]; Response.Clear(); //清除所有之前產生的Response內容 if (!string.IsNullOrEmpty(action)) { switch (action) { case "getTime": Response.Write(GetTime()); break; case "getDate": Response.Write(GetDate()); break; } } Response.End(); //停止Response後續寫入動作,保證Response內只有我們寫入內容 } private string GetDate() { return DateTime.Now.ToShortDateString(); } private string GetTime() { return DateTime.Now.ToShortTimeString(); } }}
然後為Default.aspx添加一個新的方法,並修改button的onclick方法為新寫的函數
function testGet2() { $.ajax({ type: 'get', url: 'NormalPage.aspx', async: true, data:{action:'getTime'}, success: function (result) { setContainer(result); }, error: function () { setContainer('ERROR!'); } }); }
testGet2函數是在testGet函數的基礎上做了些許修改,首先對success方法做了更改,把得到的response寫到頁面;然後對請求添加了data參數,請求向伺服器發送了一個action:getTime的索引值對,在get請求中jQuery會把此參數轉為url的參數,上面寫法和這種寫法效果一樣
function testGet3() { $.ajax({ type: 'get', url: 'NormalPage.aspx?action=getTime', async: true, success: function (result) { setContainer(result); }, error: function () { setContainer('ERROR!'); } }); }
看一下執行效果,這是Chrome的監視結果
如果調試我們發現這個請求調用的伺服器頁面NormalPage.aspx的GETime方法,並且response中只包含對有用的資料,如果把請求中參數的值改為getDate,那麼就會調用對應GetDate方法。
$.ajax POST與json
這樣向一個頁面發送請求然後在Load事件處理常式中根據參數調用不同方法,清除Response,寫入Response,終止Response,而且傳入的參數局限性太大,好業餘的趕腳,看看專業些解決方案。為project添加一個General Handler類型檔案,關於HttpHandler相關內容本文不做詳細解釋,只需知道它可以非常輕量級的處理HTTP請求,不用走繁瑣的頁面生命週期處理各種非必需資料。
Handler.ashx.cs
using System;using System.Collections.Generic;using System.Linq;using System.Web;using Newtonsoft.Json;namespace Web{ /// <summary> /// Summary description for Handler /// </summary> public class Handler : IHttpHandler { public void ProcessRequest(HttpContext context) { Student stu = new Student(); int Id = Convert.ToInt32(context.Request.Form["ID"]); if (Id == 1) { stu.Name = "Byron"; } else { stu.Name = "Frank"; } string stuJsonString= JsonConvert.SerializeObject(stu); context.Response.Write(stuJsonString); } public bool IsReusable { get { return false; } } }}
關於這個類文法本文不做詳細說明,每次發起HTTP請求ProcessRequest方法都會被調用到,Post類型請求參數和一再Request對象的Form中取得,每次根據參數ID值返回對應json對象字串,為了展示json格式資料互動,需要為項目引入json.net這一開源類庫處理對象序列化還原序列化問題,然後建立一個Student類檔案
Student.cs
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace Web{ public class Student { public int ID { get; set; } public string Name { get; set; } }}
看看頁面如何處理
function testPost() { $.ajax({ type: 'post', url: 'Handler.ashx', async: true, data: { ID: '1' }, success: function (result) { setContainer(result); var stu =eval ('('+result+')'); setContainer(stu.ID); setContainer(stu.Name); }, error: function () { setContainer('ERROR!'); } }); }
結果是這個樣子的
上面代碼向Handler.ashx發送一Post請求,比且帶有參數{ID:’1’},可以看到結果,如果用調試工具可以發現,得到的result是一個json格式的字串,也就是往Response寫的對象序列化後的結果。這樣就實現了比較專業些的方式調用Ajax,但是有一個問題依舊存在,HttpHandler會自動調用ProcessRequest方法,但是也只能調用該方法,如果想調用不同方法只能像普通頁面那樣傳遞一個參數表明調用哪個方法,或者寫不同的Handler檔案。
WebService與ScriptManager
微軟向來很貼心,看看微軟怎麼處理上面的困惑,那就是利用WebService,WebService配合SCriptManager有用戶端調用的能力,在項目中添加一個Webservice檔案
WebService.asmx
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Services;namespace Web{ /// <summary> /// Summary description for WebService /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. [System.Web.Script.Services.ScriptService] public class WebService : System.Web.Services.WebService { [WebMethod] public Student GetStudent(int ID) { if (ID == 1) { return new Student() { ID = 1, Name = "Byron" }; } else { return new Student() { ID = 2, Name = "Frank" }; } } [WebMethod] public string GetDateTime(bool isLong) { if (isLong) { return DateTime.Now.ToLongDateString(); } else { return DateTime.Now.ToShortDateString(); } } }}
代碼中加黃的code預設是被注釋掉的,要想讓用戶端調用需要把注釋去掉,Service中定義了兩個方法,寫個測試方法讓用戶端調用第一個方法根據參數返回對應對象,首先需要在頁面from內加上ScriptManager,引用剛才寫的WebService檔案
Default.aspx
<form id="form1" runat="server"> <asp:ScriptManager ID="clientService" runat="server"> <Services> <asp:ServiceReference Path="~/WebService.asmx" /> </Services> </asp:ScriptManager> <div id="container"> <input type="button" value="Test Ajax" onclick="testPost2()" /> <br /> </div>...
然後添加JavaScript測試代碼
function testPost2() { Web.WebService.GetStudent(1, function (result) { setContainer(result.ID); setContainer(result.Name); }, function () { setContainer('ERROR!'); }); }
測試代碼中需要顯示書寫WebService定義方法完整路徑,WebService命名空間.WebService類名.方法名,而出入的參數列表前幾個是調用方法的參數列表,因為GetStudent只有一個參數,所以唯寫一個,如果有兩個參數就順序寫兩個,另外兩個參數可以很明顯看出來是響應成功/失敗處理常式。看看執行結果:
觀察仔細會發現使用ScriptManager和WebService組合有福利,在WebService中傳回Student對象的時候並沒有序列化成字串,而是直接返回,看上面圖發現對象已經自動轉換為一json對象,result結果可以直接操作,果真非常貼心。而上一個例子中我們得到的response是一個json字串,在用戶端需要用eval使其轉換為json對象。
ScriptManager+WebSefvice調用ajax帶來了很大的便利性,但同時犧牲了很多靈活性,我們沒法像jQuery那樣指定很多設定有沒有兩全其美的辦法呢
$.ajax+WebService
jQuery調用Handler幾乎完美了,但是不能處理多個方法,上面例子我們可以發現WebService可以實現這一功能,那麼能不能jQUery調用WebService的不同方法呢?答案是肯定的,試一試用jQuery調用剛才WebService定義的第二個方法。寫一個測試函數
function testPost3() { $.ajax({ type: 'post', url: 'WebService.asmx/GetDateTime', async: true, data: { isLong: true }, success: function (result) { setContainer($(result).find('string').text()); }, error: function () { setContainer('ERROR!'); } }); }
調用方式沒有多大變化,簡單依舊,只要把URL改為WebService路徑+需要調用的方法名,然後把參數放到data裡就可以了。我們看看結果:
通過可以看到,jQuery調用WebService預設會返回一個XML文檔,而需要的資料在 <string>節點中,只需要使用jQuery解析xml的文法就可以輕鬆得到資料。如果希望返回一個json對象怎麼辦?那就得和調用Handler一樣使用json.net序列化,然後前端使用eval轉換了,也不會過於複雜。我在項目中最常使用這個模式,這樣既保持了jQuery的靈活性又可以在一個Service中書寫多個方法供調用,還不用走複雜的頁面生命週期
json.net和本文樣本原始碼
json.net是一個開源的.net平台處理json的庫,可以序列化Dictionay嵌套等複雜物件,關於其簡單使用有時間會總結一下,可以自codeplex上得到其源碼和官方說明。本文的原始碼可以點擊這裡獲得。