《Pro ASP.NET MVC 3 Framework》學習筆記之三十二 【無入侵的Ajax】


Ajax是Asynchronous JavaScript and XML的縮寫,正如我們看到的,XML部分已經不再像過去那樣重要,但是異步的部分卻讓Ajax非常有用。它是一種在后台從服務端請求數據的模型,而不用重新加載網頁。

使用MVC無入侵的Ajax(Using MVC Unobtrusive Ajax)
MVC框架包含了對無入侵的Ajax的支持,而且是基於jQuery庫的。下面創建示例項目UnobtrusiveAjax,如下:

View Code
復制代碼
//model
using System.ComponentModel.DataAnnotations;

namespace UnobtrusiveAjax.Models
{
    public class Appointment
    {
        public string ClientName { get; set; }
        [DataType(DataType.Date)]
        public DateTime Date { get; set; }
        public bool TermsAccepted { get; set; }
    }
}
//Controller
using System.Web.Mvc;
using UnobtrusiveAjax.Models;

namespace UnobtrusiveAjax.Controllers
{
    public class AppointmentController : Controller
    {
        //
        // GET: /Appointment/

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(string id)
        {
            return View("Index", (object)id);
        }

        public ViewResult AppointmentData(string id)
        {
            IEnumerable<Appointment> data = new[] {
                 new Appointment { ClientName = "張三", Date = DateTime.Parse("1/1/2012")}, 
                 new Appointment { ClientName = "李四", Date = DateTime.Parse("2/1/2012")}, 
                 new Appointment { ClientName = "王五", Date = DateTime.Parse("3/1/2012")}, 
                 new Appointment { ClientName = "趙六", Date = DateTime.Parse("1/20/2012")}, 
                 new Appointment { ClientName = "田七", Date = DateTime.Parse("1/22/2012")}, 
                 new Appointment {ClientName = "黃九", Date = DateTime.Parse("2/25/2012")}, 
                 new Appointment {ClientName = "路人甲", Date = DateTime.Parse("2/25/2013")}
            };
            if (!string.IsNullOrEmpty(id) && id != "All")
            {
                data = data.Where(e => e.ClientName == id);
            }
            return View(data);
        }
    }
}

//Index.cshtml
@model string
@{
    ViewBag.Title = "Index";
}
<h4>
    Appointment List</h4>
@using (Html.BeginForm())
{
    <table>
        <thead>
            <th>
                Client Name
            </th>
            <th>
                Appointment Date
            </th>
        </thead>
        <tbody id="tabledata">
            @Html.Action("AppointmentData", new { id = Model })
        </tbody>
    </table>
    <p>
        @Html.DropDownList("id", new SelectList(new[] { "All", "張三", "李四", "王五" }, (Model ?? "All")))
        <input type="submit" value="Submit" />
    </p> 
}

//AppointmentData.cshtml  部分視圖
@using UnobtrusiveAjax.Models
@model IEnumerable<Appointment>
@foreach (Appointment appt in Model)
{
    <tr>
        <td>
            @Html.DisplayFor(m => appt.ClientName)
        </td>
        <td>
            @Html.DisplayFor(m => appt.Date)
        </td>
    </tr>
}
復制代碼

運行效果如下:


上面沒有用到Ajax,僅僅是從dropdownlist里面選擇一項然后提交,瀏覽器會將form表單傳遞給服務器,程序呈現一個經過篩選的視圖並發送給瀏覽器。

啟用/禁用無入侵的Ajax(Enabling and Disabling Unobtrusive Ajax)
處理啟用/禁用Ajax的過程類似於前面對客戶端驗證的處理,配置如下:
<configuration>
  <appSettings>
    <add key="ClientValidationEnabled" value="true"/>  
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>  
  </appSettings>
...
我們還可以在controller,view或Global.asax里面通過程序控制。此外我們必須引入必要的js庫,最簡便的方式就是在_layout里面:

View Code
復制代碼
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="http://www.cnblogs.com/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
</head>
<body>
    @RenderBody()
</body>
</html>
復制代碼

使用無入侵的Ajax表單(Using Unobtrusive Ajax Forms)
Ajax最常用的地方就是處理HTML表單,創建一個啟用Ajax的表單需要兩步:①創建一個AjaxOptions對象,通過它來指定具體的Ajax請求的行為。②替換Html.BeginForm為Ajax.BeginForm,如下:

View Code
復制代碼
@model string
@{
    ViewBag.Title = "Index";
    AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tabledata" };
}
<h4>
    Appointment List</h4>
@using (Ajax.BeginForm("AppointmentData",ajaxOpts))
{
    <table>
        <thead>
            <th>
                Client Name
            </th>
            <th>
                Appointment Date
            </th>
        </thead>
        <tbody id="tabledata">
            @Html.Action("AppointmentData", new { id = Model })
        </tbody>
    </table>
    <p>
        @Html.DropDownList("id", new SelectList(new[] { "All", "張三", "李四", "王五" }, (Model ?? "All")))
        <input type="submit" value="Submit" />
    </p> 
}
復制代碼

AjaxOptions類有一套屬性讓我們能夠配置對服務器如何進行異步請求以及如何處理返回的數據。下面是列舉的屬性:
Confirm:在請求之前發送一個確認對話框給用戶
HttpMethod:設置請求的HTTP方法(Get/Post)
InsertionMode:指定從服務器檢索的內容插入HTML的方式,有三種:①InsertAfter  ②InsertBefore  ③Replace(默認)
LoadingElementId:指定在Ajax請求執行展示的HTML元素的ID
LoadingElementDuration:指定通過LoadingElementId設置的元素展示的時間(毫秒)
UpdateTargetId:設置從服務器檢索的內容插入到HTML元素的ID
Url:設置請求的URL
在上面的例子中,我們設置的UpdateTargetId屬性是"tabledata",這個Id指向了tbody元素。當從服務器獲取到內容時,我們從AppointmentData action方法獲取的數據會被替換掉(當我們從下拉框里選擇一個人篩選,提交以后原來table里面的行會被替換成篩選以后的數據)。

理解無入侵的Ajax的工作原理(Understanding How Unobtrusive Ajax Works)
可以先看下頁面的部分源碼:
<form action="/Appointment/AppointmentData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tabledata" id="form0" method="post"> 
jquery.unobtrusive-ajax.js會掃描HTML Dom並且通過尋找值為true的data-ajax屬性來識別Ajax表單。其他的指定的以data-ajax開始的屬性的值使用AjaxOptions類,這些配置項被用於配置jQuery。
跟前面使用客戶端驗證一樣,Ajax的使用是可選的。我可以直接使用jQuery或其他的js庫,或者直接寫js調用。但是,推薦不要在同一個View里面混合使用,因為這樣可能會有一些糟糕的交互,如復制或丟棄Ajax請求。

禁用無入侵的Ajax的影響(THE EFFECT OF DISABLING UNOBTRUSIVE AJAX)
在MVC之前的版本對Ajax的支持不是無入侵的。而是添加關於如何執行Ajax請求的詳情(包括使用的JSON數據和js代碼)到HTML,如果我們禁用了無入侵的Ajax功能,調用Ajax方法將會使用舊的方式。例如,下面是禁用了以后生成的form元素:

<form action="/Appointment/AppointmentData" id="form0" method="post" onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));" 
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event),
{insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: &#39;tabledata&#39; });
">

 另外,還有下面的腳本也會添加到HTML:

復制代碼
<script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[],"FormId":"form0","ReplaceValidation
Summary":false});
//]]>
</script> 
復制代碼

這些添加的內容必須是在視圖里面引入了MicrosoftAjax.js和MicrosoftMvcAjax.js庫才會起作用,否則form表單會同步提交到服務器而不是異步的。

設置Ajax選項(Setting Ajax Options)
我可以通過設置AjaxOptions對象的屬性值來調整ajax請求的行為。
確保優雅的降級(Ensuring Graceful Degradation)(這里不知道怎么翻譯合適,請大家指導)
但我們設置了啟用了Ajax的表單時,傳遞了一個action方法名參數。在上面的例子里面是AppointmentData方法。使用這種方式的一個問題就是如果用戶禁用了js或者瀏覽器不支持js,那么它就不能很好的運行了。瀏覽器會丟棄當前的HTML頁並用指定的action方法(這里就是AppointmentData)的返回結果替換。想簡單的展現這樣的類似的效果,可以直接請求~/Appointment/AppointmentData。
下面是使用AjaxOptions.Url來保證比較優雅的降級(當禁用了js的時候)

復制代碼
//加粗的部分是修改后的
@model string @{ ViewBag.Title = "Index"; AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tabledata",Url=Url.Action("AppointmentData") }; } <h4> Appointment List</h4> @using (Ajax.BeginForm(ajaxOpts)) {...
復制代碼

運行程序,禁用js,點擊提交頁面會正常顯示,雖然不是異步的。如果不做上面的修改,直接禁用掉js。效果跟上面的直接請求~/Appointment/AppointmentData是一樣的。
我們使用Url.Action方法創建一個調用了AppointmentData的Url,並使用接收一個AjaxOptions參數的重載。這個版本的重載創建一個回發的表單給呈現視圖的action方法,也就是這里的Index。當我們啟用了js,則會異步提交,產生好的用戶體驗。

使用Ajax請求時給用戶提供一個反饋(Providing the User with Feedback While Making an Ajax Request)
使用Ajax的一個弊端就是用戶不能很明確的知道發生了什么,我們可以使用AjaxOptions.LoadingElementId屬性來補救。修改Index.cshtml如下:

View Code
@model string
@{
    ViewBag.Title = "Index";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        UpdateTargetId = "tabledata",
        Url = Url.Action("AppointmentData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 2000
    };
}
<h4>
    Appointment List</h4>
<div id="loading" style="display: none; color: Red; font-weight: bold">
    <p>
        Loading Data...</p>
</div>
@using (Ajax.BeginForm(ajaxOpts))
{
    <table>
        <thead>
            <th>
                Client Name
            </th>
            <th>
                Appointment Date
            </th>
        </thead>
        <tbody id="tabledata">
            @Html.Action("AppointmentData", new { id = Model })
        </tbody>
    </table>
    <p>
        @Html.DropDownList("id", new SelectList(new[] { "All", "張三", "李四", "王五" }, (Model ?? "All")))
        <input type="submit" value="Submit" />
    </p> 
}

請求之前提示用戶(Prompting the User Before Making a Request)
AjaxOptions.Confirm屬性可以用在用戶異步請求之前給用戶一個提示信息。示例如下:

復制代碼
@model string
@{
    ViewBag.Title = "Index";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        UpdateTargetId = "tabledata",
        Url = Url.Action("AppointmentData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 2000,
        Confirm="你希望請求新的數據嗎?"
    };
}
復制代碼

創建Ajax鏈接(Creating Ajax Links)
不僅可以創建啟用了Ajax的表單,還能異步創建錨元素。修改Index.cshtml如下:

View Code
@model string
@{
    ViewBag.Title = "Index";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        UpdateTargetId = "tabledata",
        Url = Url.Action("AppointmentData"),
        LoadingElementId = "loading"
    };
}
<h4>
    Appointment List</h4>
<div id="loading" style="display: none; color: Red; font-weight: bold">
    <p>
        Loading Data...</p>
</div>
@using (Ajax.BeginForm(ajaxOpts))
{
    <table>
        <thead>
            <th>
                Client Name
            </th>
            <th>
                Appointment Date
            </th>
        </thead>
        <tbody id="tabledata">
            @Html.Action("AppointmentData", new { id = Model })
        </tbody>
    </table>
    <p>
        @Html.DropDownList("id", new SelectList(new[] { "All", "張三", "李四", "王五" }, (Model ?? "All")))
        <input type="submit" value="Submit" />
    </p> 
}
@foreach (string str in new[] { "All", "張三", "李四", "王五" })
{
    <div style="margin-right: 5px; float: left">
        @Ajax.ActionLink(str, "AppointmentData", new { id = str },
            new AjaxOptions
            {
                UpdateTargetId = "tabledata",
                LoadingElementId = "loading",
            })
    </div>
}

我們使用了一個foreach循環來創建一個div,里面包含的項跟下拉框里面是一樣的。生成的HTML為:

View Code
<div style="margin-right: 5px; float: left">
        <a data-ajax="true" data-ajax-loading="#loading" data-ajax-mode="replace" data-ajax-update="#tabledata" href="/Appointment/AppointmentData/All">All</a>
    </div>
    <div style="margin-right: 5px; float: left">
        <a data-ajax="true" data-ajax-loading="#loading" data-ajax-mode="replace" data-ajax-update="#tabledata" href="/Appointment/AppointmentData/%E5%BC%A0%E4%B8%89">張三</a>
    </div>
    <div style="margin-right: 5px; float: left">
        <a data-ajax="true" data-ajax-loading="#loading" data-ajax-mode="replace" data-ajax-update="#tabledata" href="/Appointment/AppointmentData/%E6%9D%8E%E5%9B%9B">李四</a>
    </div>
    <div style="margin-right: 5px; float: left">
        <a data-ajax="true" data-ajax-loading="#loading" data-ajax-mode="replace" data-ajax-update="#tabledata" href="/Appointment/AppointmentData/%E7%8E%8B%E4%BA%94">王五</a>
    </div>

當我點擊下面生成的鏈接時,效果跟上面選擇一個下拉框的選項提交的效果一樣。

對鏈接確保優雅降級(Ensuring Graceful Degradation for Links)
類似與前面針對表單的優雅降級,如果js被禁用了,點擊上面生成的鏈接,會跟請求~/Appointment/AppointmentData一樣。可以同樣使用
Url = Url.Action("AppointmentData", new { id = str}) 來處理。修改Index.cshtml如下:

復制代碼
@foreach (string str in new[] { "All", "張三", "李四", "王五" })
{
    <div style="margin-right: 5px; float: left">
        @Ajax.ActionLink(str, "Index", new { id = str },
            new AjaxOptions
            {
                UpdateTargetId = "tabledata",
                LoadingElementId = "loading",
               Url = Url.Action("AppointmentData", new { id = str })
            })
    </div>
}
復制代碼

通過為每一個鏈接創建一個單獨的AjaxOptions對象,我們可以指定路由的值以至於每一個鏈接都是一個單一的請求。這非常有用,因為我們的鏈接不是Form的一部分(查看源代碼可以看到div在form表單外面)。我們還需要修改下控制器。當javascript禁用的時候,點擊鏈接產生一個Get請求,會直接導向沒有參數的Index控制器,而這個控制器是沒有任何數據篩選邏輯的,所以不會對提交產生任何效果。修改如下:

復制代碼
//public ActionResult Index()
//{
//    return View();
//}

//[HttpPost]
public ActionResult Index(string id)
{
     return View("Index", (object)id);
}
復制代碼

使用Ajax回調(Working with Ajax Callbacks)
AjaxOptions類定義了一套屬性,讓我們指定Ajax請求生命周期的多個點上調用的javascript函數。如下:

  屬性名 jQuery事件 描述
OnBegin beforeSend 請求發出之前調用
OnComplete complete 請求成功以后調用
OnFailure error 請求失敗以后調用
OnSuccess success 請求完成后調用,不考請求是否成功或失敗

 

 

 



每一個Ajax回調屬性關聯了一個jQuery支持的Ajax事件,想了解更多的內容可以點擊這里
使用Ajax回調的第一步就是創建我們想調用的javascript函數。我們在_Layout.cshtml里面添加了script元素,如下:

View Code
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="http://www.cnblogs.com/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        function OnBegin() {
            alert("這是OnBegin回調");
        }

        function OnSuccess(data) {
            alert("這是OnSuccess回調: " + data);
        }

        function OnFailure(request, error) {
            alert("這是OnFailure回調:" + error);
        }

        function OnComplete(request, status) {
            alert("這是OnComplete回調: " + status);
        } 
    </script>
</head>
<body>
    @RenderBody()
</body>
</html>

我們定義了4個函數,每一個針對一個回調。為了將這些函數跟回調掛鈎,我們指定函數的名稱跟AjaxOptions屬性的值一致,如下:

復制代碼
@foreach (string str in new[] { "All", "張三", "李四", "王五" })
{
    <div style="margin-right: 5px; float: left">
        @Ajax.ActionLink(str, "Index", new { id = str },
            new AjaxOptions
            {
                UpdateTargetId = "tabledata",
                LoadingElementId = "loading",
                Url = Url.Action("AppointmentData", new { id = str }),
                OnBegin = "OnBegin",
                OnFailure = "OnFailure",
                OnSuccess = "OnSuccess",
                OnComplete = "OnComplete"
            })
    </div>
}
復制代碼

運行程序,點擊一個鏈接會看到一序列的窗口如下:

使用JSON(Working with JSON)
到目前為止,服務端都是呈現一個HTML片段並發送給瀏覽器,這是最常使用和被接受的技術,但是如果我們想使用服務端返回的數據做更多的事情,需要使用JSON數據格式來方便的我們的操作。了解JSON
添加JSON支持到控制器(Adding JSON Support to the Controller)
MVC里面生成JSON數據的action方法非常簡便,如下例:

View Code
using System.Web.Mvc;
using UnobtrusiveAjax.Models;

namespace UnobtrusiveAjax.Controllers
{
    public class AppointmentController : Controller
    {
        //
        // GET: /Appointment/

        //public ActionResult Index()
        //{
        //    return View();
        //}

        //[HttpPost]
        public ActionResult Index(string id)
        {
            return View("Index", (object)id);
        }

        public ViewResult AppointmentData(string id)
        {
            IEnumerable<Appointment> data = new[] {
                 new Appointment { ClientName = "張三", Date = DateTime.Parse("1/1/2012")}, 
                 new Appointment { ClientName = "李四", Date = DateTime.Parse("2/1/2012")}, 
                 new Appointment { ClientName = "王五", Date = DateTime.Parse("3/1/2012")}, 
                 new Appointment { ClientName = "趙六", Date = DateTime.Parse("1/20/2012")}, 
                 new Appointment { ClientName = "田七", Date = DateTime.Parse("1/22/2012")}, 
                 new Appointment {ClientName = "黃九", Date = DateTime.Parse("2/25/2012")}, 
                 new Appointment {ClientName = "路人甲", Date = DateTime.Parse("2/25/2013")}
            };
            if (!string.IsNullOrEmpty(id) && id != "All")
            {
                data = data.Where(e => e.ClientName == id);
            }
            return View(data);
        }

        public JsonResult JsonData(string id)
        {
            IEnumerable<Appointment> data = new[] {
                 new Appointment { ClientName = "張三", Date = DateTime.Parse("1/1/2012")}, 
                 new Appointment { ClientName = "李四", Date = DateTime.Parse("2/1/2012")}, 
                 new Appointment { ClientName = "王五", Date = DateTime.Parse("3/1/2012")}, 
                 new Appointment { ClientName = "趙六", Date = DateTime.Parse("1/20/2012")}, 
                 new Appointment { ClientName = "田七", Date = DateTime.Parse("1/22/2012")}, 
                 new Appointment {ClientName = "黃九", Date = DateTime.Parse("2/25/2012")}, 
                 new Appointment {ClientName = "路人甲", Date = DateTime.Parse("2/25/2013")}
            };
            if (!string.IsNullOrEmpty(id) && id != "All")
            {
                data = data.Where(e => e.ClientName == id);
            }
            var formattedData = data.Select(m => new
            {
                Client = m.ClientName,
                Date = m.Date.ToShortDateString(),
                TermsAccepted = m.TermsAccepted
            });

            return Json(formattedData, JsonRequestBehavior.AllowGet);
        }
    }
}

我們添加了一個新的action方法JsonData,返回一個JsonResult的對象。通過調用Json()來創建一個JsonResult,把傳入的數據轉換為Json格式。像這樣:
return Json(formattedData, JsonRequestBehavior.AllowGet);
在這個例子中,我們傳遞了JsonRequestBehavior.AllowGet的枚舉值。默認情況下,JSON數據僅僅在響應POST請求時發送,傳遞這個枚舉值就告訴MVC框架響應Get請求並傳遞Json數據。

注意:我們應該在返回的數據不是私人的,可以公開的數據時使用JsonRequestBehavior.AllowGet。因為這存在一個安全問題,第三方的站點是可以截取響應Get請求時返回的JSON數據,這也是為什么默認情況下只響應Post請求的JSON數據。大多數情況下,我們能夠使用POST請求檢索JSON數據,並且避免了這個問題。

返回JsonResult的action方法和其他生成HTML的方法有個不同的地方——使用了LINQ創建一個匿名的類型。像這樣:
var formattedData = data.Select(m => new
{
    ClientName = m.ClientName,
    Date = m.Date.ToShortDateString(),
    TermsAccepted = m.TermsAccepted
});
有兩個理由讓我們在這里使用匿名類型的對象:①客戶端不需要用TermsAccepted屬性,所以也就不需要把它發送到客戶端。②經過這樣的處理后可以使得客戶端處理JSON數據更加簡單。當MVC框架使用JSON編碼一個Datetime值時,處理的有點奇怪,會呈現下面的內容:
{"ClientName":"Joe","Date":"/Date(1325376000000)/","TermsAccepted":false}
這個不尋常的日期格式使得在客戶端轉換為javascript Date對象更加容易,然后進行操作。其實,我們不需要在客戶端對Date進行操作,我們只用把它作為字符串展示就OK,並且將Date轉為String操作在服務端更加容易。我們可以通過URL來查看生成的JSON數據,如:

在瀏覽器端處理JSON(Processing JSON in the Browser)
為了處理檢索的JSON數據,我們使用OnSuccess回調屬性在AjaxOptions類里面指定一個javascript函數,如下:

復制代碼
@foreach (string str in new[] { "All", "張三", "李四", "王五" })
{
    <div style="margin-right: 5px; float: left">
        @Ajax.ActionLink(str, "Index", new { id = str },
            new AjaxOptions
            {
                LoadingElementId = "loading",
                Url = Url.Action("JsonData", new { id = str }),
                OnSuccess = "OnSuccess"
            })
    </div>
}
復制代碼

注意:這里沒有給UpdateTargetId屬性賦值,我們不能依靠無入侵的ajax腳本來處理JSON數據,因為這些數據不是HTML。相反我們需要寫一個js函數來處理JSON並生成我們需要的HTML,如下:

View Code
    <script type="text/javascript"> function OnBegin() { alert("這是OnBegin回調"); } function OnSuccess(data) { var target = $("#tabledata"); target.empty(); for (var i = 0; i < data.length; i++) { target.append('<tr><td>' + data[i].ClientName + '</td><td>'
                + data[i].Date + '</td></tr>'); } } function OnFailure(request, error) { alert("這是OnFailure回調:" + error); } function OnComplete(request, status) { alert("這是OnComplete回調: " + status); } </script>

在Action方法里探測Ajax請求(Detecting Ajax Requests in the Action Method)
我們不必創建兩個action方法來分別生成JSON和HTML,可以探測請求是否是Ajax請求並發送JSON,並同時針對其他的請求發送HTML。下面用AppointmentData來說明:

View Code
        public ActionResult AppointmentData(string id)
        {
            IEnumerable<Appointment> data = new[] {
                 new Appointment { ClientName = "張三", Date = DateTime.Parse("1/1/2012")}, 
                 new Appointment { ClientName = "李四", Date = DateTime.Parse("2/1/2012")}, 
                 new Appointment { ClientName = "王五", Date = DateTime.Parse("3/1/2012")}, 
                 new Appointment { ClientName = "趙六", Date = DateTime.Parse("1/20/2012")}, 
                 new Appointment { ClientName = "田七", Date = DateTime.Parse("1/22/2012")}, 
                 new Appointment {ClientName = "黃九", Date = DateTime.Parse("2/25/2012")}, 
                 new Appointment {ClientName = "路人甲", Date = DateTime.Parse("2/25/2013")}
            };
            if (!string.IsNullOrEmpty(id) && id != "All")
            {
                data = data.Where(e => e.ClientName == id);
            }

            if (Request.IsAjaxRequest())
            {
                return Json(data.Select(m => new
                {
                    ClientName = m.ClientName,
                    Date = m.Date.ToShortDateString()
                }), JsonRequestBehavior.AllowGet);
            }
            else
            {
                return View(data);
            }

        }

此時修改Index部分如下(加粗部分):

復制代碼
@foreach (string str in new[] { "All", "張三", "李四", "王五" })
{
    <div style="margin-right: 5px; float: left">
        @Ajax.ActionLink(str, "Index", new { id = str },
            new AjaxOptions
            {
                LoadingElementId = "loading",
                Url = Url.Action("AppointmentData", new { id = str }),
                OnSuccess = "OnSuccess"
            })
    </div>
}
復制代碼

接收JSON數據(Receiving JSON Data)
大多數情況下,我們想發送JSON數據到客戶端。我們也能夠很容易處理反過來的情況,MVC框架的模型綁定系統能夠使用JSON數據綁定到一個model類。下面的例子就是包含一個提交一個JSON對象到action方法的jQuery腳本:

View Code
//HomeController
using System.Web.Mvc;
using UnobtrusiveAjax.Models;

namespace UnobtrusiveAjax.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View(new Appointment());
        }

        [HttpPost]
        public ActionResult Index(Appointment app)
        {
            if (Request.IsAjaxRequest())
            {
                return Json(new
                {
                    ClientName = app.ClientName,
                    Date = app.Date.ToShortDateString(),
                    TermsAccepted = app.TermsAccepted
                });
            }
            else
            {
                return View();
            }
        }

    }
}

//Index.cshtml
@using UnobtrusiveAjax.Models
@model Appointment
<script type="text/javascript">
    $(document).ready(function () {
        $("form").submit(function (e) {
            e.preventDefault();
            var appointment = {
                ClientName: $("#ClientName").val(),
                Date: $("#Date").val(),
                TermsAccepted: $("#TermsAccepted").is(":checked")
            };

            $.ajax({
                url: '@Url.Action("Index")',
                type: "POST",
                data: JSON.stringify(appointment),
                dataType: "json",
                processData: false,
                contentType: "application/json; charset=utf-8",
                success: function (data) {
                    $("#clienttarget").text(data.ClientName);
                    $("#datetarget").text(data.Date);
                    $("#termstarget").text(data.TermsAccepted);
                    $("#results").show();
                },
            });
        });
    });
</script>
<h4>
    創建Appointment</h4>
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" value="提交" />
}
<div id="results" style="display: none">
    這是你創建的預約:
    <p>
        ClientName: <span id="clienttarget" />
    </p>
    <p>
        Date: <span id="datetarget" />
    </p>
    <p>
        Terms Accepted: <span id="termstarget" />
    </p>
</div>

Tip:上面的腳本依賴JSON.stringify函數,這個函數在大多數瀏覽器可用,但是在IE7及之前版本的瀏覽器不支持。這時可以引入json2.js庫來支持,點這里下載

模型綁定系統能夠識別JSON數據並以綁定form數據和querystring數據同樣的方式綁定JSON數據,我們不需要做任何特別的操作來接收JSON數據,binder會創建Appointment對象,並使用JSON對象的值來填充屬性。然后又把Appointment對象轉為JSON返回給客戶端。運行程序可以看到效果。

本章的筆記就到這里了,晚安!


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com