共用方式為


使用 AJAX 傳送動態更新

Microsoft 提供

下載 PDF

這是免費的 "NerdDinner" 應用程式教學課程的第 10 個步驟,詳細介紹了如何使用 ASP.NET MVC 1 建置一個小型但完整的 Web 應用程式。

步驟 10 使用整合在 Dinner 詳細資料頁面中的基於 Ajax 的方法,實現對登入使用者的支援,以回應他們參加 Dinner 的興趣 ...

如果使用 ASP.NET MVC 3,建議遵循 MVC 3 使用者入門MVC Music 市集教學課程。

NerdDinner 步驟 10:啟用 RSVP 接受的 AJAX

現在讓我們實作對已登入使用者的支援,以便他們可以回覆有興趣參加 Dinner。 我們將使用整合在 Dinner 詳細資料頁面中的 AJAX 方法來啟用此功能。

指示使用者是否已回覆參加。

使用者可以造訪 /Dinners/Details/[id] URL,以查看特定 Dinner 的詳細資料:

Nerd Dinner 網頁的螢幕擷取畫面,其中包含 Dinner 的詳細資料。

Details() 動作方法的實作如下:

//
// GET: /Dinners/Details/2

public ActionResult Details(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (dinner == null)
        return View("NotFound");
    else
        return View(dinner);
}

實現回覆支援的第一步是在我們的 Dinner 物件中新增一個 IsUserRegistered(username) 協助程式方法 (在我們之前建立的 Dinner.cs 部分類別中)。 此協助程式方法根據使用者目前是否已回覆 Dinner 來返回 true 或 false:

public partial class Dinner {

    public bool IsUserRegistered(string userName) {
        return RSVPs.Any(r => r.AttendeeName.Equals(userName, StringComparison.InvariantCultureIgnoreCase));
    }
}

然後,我們可以將下列程式碼新增至 Details.aspx 檢視範本,以顯示指出使用者是否已註冊該事件的適當訊息:

<% if (Request.IsAuthenticated) { %>
 
    <% if (Model.IsUserRegistered(Context.User.Identity.Name)) { %>       

        <p>You are registred for this event!</p>
    
    <% } else {  %>  
    
        <p>You are not registered for this event</p>
        
    <% }  %>
    
<% } else { %>
 
    <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>

現在,當使用者造訪他們註冊的 Dinner 時,就會看到此訊息:

Nerd Dinners 詳細資料頁面的螢幕擷取畫面,底部顯示 [您已註冊此事件] 的訊息。

當他們造訪沒有註冊的 Dinner 時,他們不會看到此訊息:

Nerd Dinners 詳細資料頁面的螢幕擷取畫面。顯示 [您未註冊此事件] 的訊息。

實作註冊動作方法

現在讓我們新增必要的功能,以便使用者可以從詳細資料頁面回覆 Dinner。

為了實作此動作,我們將以滑鼠右鍵按一下 \Controllers 目錄並選擇新增 -> 控制器功能表命令,以建立新的 “RSVPController” 類別。

我們將在新的 RSVPController 類別內實作 [註冊] 動作方法,該方法將 Dinner 的識別碼作為引數、擷取適當的 Dinner 物件、檢查已登入的使用者目前是否在已註冊的使用者清單中,如果沒有為其新增 [回覆] 物件:

public class RSVPController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // AJAX: /Dinners/RSVPForEvent/1

    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Register(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (!dinner.IsUserRegistered(User.Identity.Name)) {
        
            RSVP rsvp = new RSVP();
            rsvp.AttendeeName = User.Identity.Name;

            dinner.RSVPs.Add(rsvp);
            dinnerRepository.Save();
        }

        return Content("Thanks - we'll see you there!");
    }
}

請注意上面我們如何傳回一個簡單的字串作為動作方法的輸出。 我們本可以將這條訊息內嵌到檢視範本,但由於它非常簡短,我們將直接使用控制器基底類別上的 Content() 協助程式方法,並返回像上面那樣的字串訊息。

使用 AJAX 呼叫 RSVPForEvent 動作方法

我們將使用 AJAX 從 [詳細資料] 檢視叫用 [註冊] 動作方法。 實作這項操作相當簡單。 首先,我們將新增兩個指令碼程式庫參考:

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

第一個程式庫會參考核心 ASP.NET AJAX 用戶端指令碼程式庫。 此檔案的大小約為 24k (壓縮),且包含核心用戶端 AJAX 功能。 第二個程式庫包含與 ASP.NET MVC 內建 AJAX 協助程式方法整合的公用程式函式 (我們很快就會使用此方法)。

然後,我們可以更新稍早新增的檢視範本程式碼,這樣就不會輸出「您未註冊此事件」訊息,而是轉譯連結,在推送時執行 AJAX 呼叫,以在 [回覆控制器] 叫用 RSVPForEvent 動作方法並回覆使用者:

<div id="rsvpmsg">

<% if(Request.IsAuthenticated) { %>
 
    <% if(Model.IsUserRegistered(Context.User.Identity.Name)) { %>       

        <p>You are registred for this event!</p>

    <% } else { %>  
    
        <%= Ajax.ActionLink( "RSVP for this event",
                             "Register", "RSVP",
                             new { id=Model.DinnerID }, 
                             new AjaxOptions { UpdateTargetId="rsvpmsg"}) %>         
    <% } %>
    
<% } else { %>
 
    <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>
    
</div>

上述使用的 Ajax.ActionLink() 協助程式方法內建於 ASP.NET MVC,而且類似於 Html.ActionLink() 協助程式方法,不同之處在於,它不會執行標準導覽,而是在按一下連結時對動作方法發出 AJAX 呼叫。 在上方,我們會在 [回覆] 控制器上呼叫 [註冊] 動作方法,並將 DinnerID 當做 "id" 參數傳遞給它。 我們傳遞的最後 AjaxOptions 參數表示我們想要取得動作方法傳回的內容,並在識別碼為 “rsvpmsg” 的頁面上更新 HTML <div> 項目。

現在當尚未註冊的使用者瀏覽至 Dinner 時,他們會看到 [回覆] 的連結:

底部有 [R S V P] 按鈕的 Nerd Dinners 頁面的擷取畫面。

如果他們按一下 [此事件的回覆] 連結,他們會對 [回覆] 控制器上的 [註冊] 動作方法進行 AJAX 呼叫,並在完成時看到更新的訊息,如下所示:

Nerd Dinner 詳細資料頁面的螢幕擷取畫面,底部顯示 [感謝我們將在那裡看到您] 訊息。

進行此 AJAX 呼叫時所涉及的網路頻寬和流量非常輕量。 當使用者按一下 [回覆此事件] 連結時,會向 /Dinners/Register/1 URL 發送一個小型的 HTTP POST 網路要求,如下所示:

POST /Dinners/Register/49 HTTP/1.1
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Referer: http://localhost:8080/Dinners/Details/49

而我們的 [註冊] 動作方法的回應只是:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 29
Thanks - we'll see you there!

這個輕量型的呼叫速度很快,即使網路速度慢也能正常工作。

新增 jQuery 動畫

我們實作的 AJAX 功能運作良好且快速。 不過,有時候會發生如此快的情況,使用者可能不會注意到 [回覆] 連結已被新的文字取代。 為了讓結果更加明顯,我們可以新增簡單的動畫來吸引人們對更新訊息的注意。

預設 ASP.NET MVC 專案範本包含 jQuery – 一個出色且非常受歡迎的開放原始碼 JavaScript 程式庫,Microsoft 也提供支援。 jQuery 提供許多功能,包括很好的 HTML DOM 選取和效果程式庫。

若要使用 jQuery,我們會先新增指令碼參考。 由於我們將在網站內的各種位置使用 jQuery,因此會在 Site.master 主版頁面檔案中新增指令碼參考,讓所有頁面都可以使用它。

<script src="/Scripts/jQuery-1.3.2.js" type="text/javascript"></script>

使用 JQuery 撰寫的程式碼通常會使用全域 "$()" JavaScript 方法,使用 CSS 選取器擷取一或多個 HTML 元素。 例如,$("#rsvpmsg") 會選取任何具有 rsvpmsg 識別碼的 HTML 元素,而$(".something") 會選取具有 “something” CSS 類別名稱的所有元素。 您也可以使用選取器查詢來撰寫更進階的查詢,例如 [傳回所有核取的選項按鈕],例如:$("input[@type=radio][@checked]")

選擇元素後,您可以呼叫它們的方法來執行操作,例如隱藏它們:$("#rsvpmsg").hide();

在我們的 [回覆] 案例中,我們將定義名為 “AnimateRSVPMessage” 的簡單 JavaScript 函式,以選取 “rsvpmsg” <div> 並建立其文字內容大小的動畫。 下列程式碼會啟動小型文字,然後使其在 400 毫秒的時間範圍內變大:

<script type="text/javascript">

    function AnimateRSVPMessage() {
        $("#rsvpmsg").animate({fontSize: "1.5em"},400);
    }

</script>

然後,我們可以在 AJAX 呼叫順利完成之後,連接此 JavaScript 函式,方法是將其名稱傳遞至 Ajax.ActionLink() 協助程式方法 (透過 AjaxOptions “OnSuccess” 事件屬性):

<%= Ajax.ActionLink( "RSVP for this event",
                     "Register", "RSVP",
                     new { id=Model.DinnerID }, 
                     new AjaxOptions { UpdateTargetId="rsvpmsg",
                                       OnSuccess="AnimateRSVPMessage"}) %>

現在,按一下 [回覆此事件] 連結,且我們的 AJAX 呼叫成功完成時,傳回的內容訊息將會以動畫顯示並變大:

Nerd Dinners 頁面的螢幕擷取畫面,底部大字體顯示 [感謝我們將在那裡看到您] 訊息。

除了提供 "OnSuccess" 事件之外,AjaxOptions 物件也會公開您可以處理的 OnBegin、OnFailure 和 OnComplete 事件 (以及其他各種屬性和實用選項)。

清除 - 重構回覆部分檢視

我們的詳細資料檢視範本開始有點長,隨著時間的推移,它會變得有點難以理解。 為了幫助提高程式碼的可讀性,讓我們最後建立一個部分視圖 RSVPStatus.ascx,它封裝了我們 [詳細資料] 頁面的所有 [回覆] 檢視程式碼。

我們可以在 \Views\Dinners 資料夾上按一下滑鼠右鍵,然後選擇新增 -> 檢視功能表命令來執行這項操作。 我們將採用 Dinner 物件作為其強型別 ViewModel。 然後,我們可以從 Details.aspx 檢視複製/貼上 [回覆] 內容。

一旦完成,我們也會建立另一個部分檢視 – EditAndDeleteLinks.ascx ,它封裝我們的 [編輯] 和 [刪除] 連結檢視程式碼。 我們也會將 Dinner 物件當作其強型別 ViewModel,並從 Details.aspx 檢視複製/貼上 [編輯] 和 [刪除] 邏輯。

然後,我們的詳細資料檢視範本就可以在底部包含兩個 Html.RenderPartial() 方法呼叫:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent"runat="server">
    <%= Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="details" ContentPlaceHolderID="MainContent" runat="server">

    <div id="dinnerDiv">

        <h2><%=Html.Encode(Model.Title) %></h2>
        <p>
            <strong>When:</strong> 
            <%=Model.EventDate.ToShortDateString() %> 

            <strong>@</strong>
            <%=Model.EventDate.ToShortTimeString() %>
        </p>
        <p>
            <strong>Where:</strong> 
            <%=Html.Encode(Model.Address) %>,
            <%=Html.Encode(Model.Country) %>
        </p>
         <p>
            <strong>Description:</strong> 
            <%=Html.Encode(Model.Description) %>
        </p>       
        <p>
            <strong>Organizer:</strong> 
            <%=Html.Encode(Model.HostedBy) %>
            (<%=Html.Encode(Model.ContactPhone) %>)
        </p>
    
        <% Html.RenderPartial("RSVPStatus"); %>
        <% Html.RenderPartial("EditAndDeleteLinks"); %>
 
    </div>
         
</asp:Content>

這可讓程式碼更清楚讀取和維護。

後續步驟

現在讓我們看看如何進一步使用 AJAX,並將互動式對應支援新增至應用程式。