使用 AJAX 提供动态更新

Microsoft

下载 PDF

这是免费的 “NerdDinner”应用程序教程 的第 10 步,介绍如何使用 ASP.NET MVC 1 生成小型但完整的 Web 应用程序。

步骤 10 使用集成在晚餐详细信息页中的基于 Ajax 的方法,对登录用户实施支持,以 RSVP 他们的兴趣参加晚宴。

如果你使用的是 ASP.NET MVC 3,我们建议你遵循入门与 MVC 3MVC 音乐应用商店教程。

NerdDinner 步骤 10:AJAX 启用 RSVP 接受

现在,让我们对登录用户实施支持,以 RSVP 他们有兴趣参加晚宴。 我们将使用集成在晚餐详细信息页中的基于 AJAX 的方法启用此功能。

指示用户是否为 RSVP'd

用户可以访问 /Dinners/Details/[id] URL 以查看有关特定晚餐的详细信息:

Nerd 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);
}

实现 RSVP 支持的第一步是将“IsUserRegistered (username) ”帮助程序方法添加到我们之前) 构建的 Dinner.cs 分部类中的 Dinner 对象 (。 此帮助程序方法返回 true 或 false,具体取决于用户当前是否是 Dinner 的 RSVP:

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 详细信息页的屏幕截图,底部显示了“已注册此事件”消息。

当他们参观晚餐时,他们没有注册,他们会看到以下消息:

Nerd Dinners 详细信息页的屏幕截图。此时会显示“未注册此事件”消息。

实现 Register 操作方法

现在,让我们添加必要的功能,使用户能够从详细信息页获得晚餐的 RSVP。

为了实现此目标,我们将通过右键单击 \Controllers 目录并选择 Add-Controller> 菜单命令来创建新的“RSVPController”类。

我们将在新的 RSVPController 类中实现一个“Register”操作方法,该方法采用 Dinner 的 ID 作为参数,检索相应的 Dinner 对象,检查登录用户当前是否在注册的用户列表中,如果没有,则为其添加 RSVP 对象:

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 从详细信息视图调用 Register 操作方法。 实现此操作非常简单。 首先,我们将添加两个脚本库引用:

<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 调用,该调用在 RSVP 控制器和 RSVP 用户上的 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 调用。 上面我们在“RSVP”控制器上调用“Register”操作方法,并将 DinnerID 作为“id”参数传递给它。 我们传递的最后一个 AjaxOptions 参数指示我们想要获取从操作方法返回的内容,并更新页面上的 HTML <div> 元素,该元素的 ID 为“rsvpmsg”。

现在,当用户浏览到尚未注册的晚餐时,他们会看到指向 RSVP 的链接:

Nerd Dinners 页面的屏幕截图,底部有“R S V P”按钮。

如果他们单击“此事件的 RSVP”链接,他们将对 RSVP 控制器上的 Register 操作方法进行 AJAX 调用,完成后,他们将看到如下所示的更新消息:

Nerd Dinner 详细信息页面的屏幕截图,底部显示“谢谢我们将在那里看到你”。

进行此 AJAX 调用时涉及的网络带宽和流量确实很轻。 当用户单击“此事件的 RSVP”链接时,会向 /Dinners/Register/1 URL 发出小型 HTTP POST 网络请求,该 URL 在网络上如下所示:

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

Register 操作方法的响应很简单:

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

这种轻量级调用速度很快,即使在慢速网络中也能正常工作。

添加 jQuery 动画

我们实现的 AJAX 功能运行良好且快速。 不过,有时它可能会发生得非常快,以至于用户可能不会注意到 RSVP 链接已替换为新文本。 为了使结果更加明显,我们可以添加一个简单的动画来吸引人们对更新消息的注意。

默认 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”) 选择 ID 为 rsvpmsg 的任何 HTML 元素,而 $ (“.something”) 将选择具有“something”CSS 类名称的所有元素。 还可以使用以下选择器查询编写更高级的查询,例如“返回所有选中的单选按钮”: $ (“input[@type=radio][@checked]”)

选择元素后,可以对其调用方法来执行操作,例如隐藏它们: $ (“#rsvpmsg”) .hide () ;

对于 RSVP 方案,我们将定义一个名为“AnimateRSVPMessage”的简单 JavaScript 函数,该函数选择“rsvpmsg” <div> 并对其文本内容的大小进行动画处理。 下面的代码从较小的文本开始,然后使文本在 400 毫秒的时间范围内增加:

<script type="text/javascript">

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

</script>

然后,我们可以通过 AjaxOptions“OnSuccess”事件属性 (将它的名称传递给 Ajax.ActionLink () 帮助程序方法,在 AJAX 调用成功完成后) 调用此 JavaScript 函数:

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

现在,当单击“此事件的 RSVP”链接并且我们的 AJAX 调用成功完成时,发送回的内容消息将进行动画处理并变大:

Nerd Dinners 页面的屏幕截图,底部显示消息“谢谢,我们将在那里看到你”。

除了提供“OnSuccess”事件外,AjaxOptions 对象还公开 OnBegin、OnFailure 和 OnComplete 事件,这些事件可以处理 (以及) 的各种其他属性和有用选项。

清理 - 重构 RSVP 分部视图

详细信息视图模板开始变得有点长,加班会使其更难理解。 为了帮助提高代码可读性,让我们创建一个分部视图 RSVPStatus.ascx,用于封装详细信息页的所有 RSVP 视图代码。

为此,可以右键单击 \Views\Dinners 文件夹,然后选择“添加视图>”菜单命令。 我们将采用 Dinner 对象作为其强类型 ViewModel。 然后,我们可以将详细信息.aspx 视图中的 RSVP 内容复制/粘贴到其中。

完成此操作后,我们还创建另一个分部视图-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,并为应用程序添加交互式映射支持。