ASP.NET MVC 4 (八) URL链接和Ajax帮助函数

使用帮助函数创建链接

MVC提供一些帮助函数创建链接,这些函数根据路径映射表自动调整生成的URL:

说明 示例 输出结果
应用程序相对URL Url.Content("~/Content/Site.css")  /Content/Site.css
到控制器action的链接 Html.ActionLink("My Link", "Index", "Home") <a href="/">My Link</a> 
Action的URL Url.Action("GetPeople", "People") /People/GetPeople 
使用路径映射的URL Url.RouteUrl(new {controller = "People", action="GetPeople"})  /People/GetPeople 
使用路径映射的链接
Html.RouteLink("My Link", new {controller = "People", action="GetPeople"})

<a href="/People/GetPeople">My Link</a>
命名路径映射的链接
Html.RouteLink("My Link", "FormRoute", new {controller = "People", action="GetPeople"})

<a href="/app/forms/People/GetPeople">My Link</a> 

使用MVC Unobtrusive Ajax

MVC内建基于jQuery的unobtrusive Ajax的支持,之所以称之为unobtrusive Ajax是因为不像常规Ajax那样大量使用XML。要使用unobtrusive Ajax,首先需要在web.config的 configuration/appSettings一节开启UnobtrusiveJavaScriptEnabled支持:

...
<configuration>
<!-- other elements omitted for brevity -->
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
</appSettings>
<!-- other elements omitted for brevity -->
</configuration>
... 

同时我们需要引用相关的javascript文件,可以把对这些脚本文件的引用放到布局文件_layout.cshtml中:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link href="~/Content/Site.css" rel="stylesheet"/>
    <script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

jquery-1.7.1.min.js为jQuery的核心库,jquery.unobtrusive-ajax.min.js则提供Ajax功能(基于jquery库),文件名中的.min表示几乎不可能调试的缩减版本,可以在开发时使用非.min版本,发布时再采用.min版本。

使用Unobtrusive Ajax表单

下面以实例演示如何使用Ajax表单,从控制器开始:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HelperMethods.Models;
namespace HelperMethods.Controllers
{
    public class PeopleController : Controller
    {
        private Person[] personData = {
new Person {FirstName = "Adam", LastName = "Freeman", Role = Role.Admin},
new Person {FirstName = "Steven", LastName = "Sanderson", Role = Role.Admin},
new Person {FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User},
new Person {FirstName = "John", LastName = "Smith", Role = Role.User},
new Person {FirstName = "Anne", LastName = "Jones", Role = Role.Guest}
};
        public ActionResult Index()
        {
            return View();
        }
        public PartialViewResult GetPeopleData(string selectedRole = "All")
        {
            IEnumerable<Person> data = personData;
            if (selectedRole != "All")
            {
                Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
                data = personData.Where(p => p.Role == selected);
            }
            return PartialView(data);
        }
        public ActionResult GetPeople(string selectedRole = "All")
        {
            return View((object)selectedRole);
        }
    }
}

GetPeopleData()方法根据选择的角色过滤Person列表,返回一个分部视图,对应的GetPeopleData.cshtml:

@using HelperMethods.Models
@model IEnumerable<Person>

@foreach (Person p in Model) {
    <tr>
        <td>@p.FirstName</td>
        <td>@p.LastName</td>
        <td>@p.Role</td>
    </tr>
}

在Getpeople视图中我们调用GetPeopleData()同时创建一个Ajax form:

@using HelperMethods.Models
@model string
@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        UpdateTargetId = "tableBody"
    };
}
<h2>Get People</h2>
<table>
    <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>
    <tbody id="tableBody">
        @Html.Action("GetPeopleData", new { selectedRole = Model })
    </tbody>
</table>
@using (Ajax.BeginForm("GetPeopleData", ajaxOpts))
{
    <div>
        @Html.DropDownList("selectedRole", new SelectList(new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
        <button type="submit">Submit</button>
    </div>
} 

Ajax.BeginForm()创建一个Ajax form,使用AjaxOptions对象作为参数,生成的HTML结果:

...
<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody"id="form0" method="post">
... 

浏览器请求GetPeople页面时jquery.unobtrusive-ajax.js扫描data-ajax=true的单元,以此确认这是一个ajax的表单,点击提交时不刷新整个页面,而是用从/people/getpeopledata返回的结果替换tablebody的内容。

Ajax options

AjaxOptions控制向服务器异步请求时的方式,包含这些属性:

属性 说明
Confirm 在开始异步请求时向用户显示一条消息以确认
HttpMethod 设置请求的HTTP方法,必须是get或者post
InsertionMode 如何嵌入服务器结果返回的HTML,可以是InsertAfter、InsertBefore、Replace(默认)
LoadingElementId 指定Ajax请求时要显示的Loading单元元素ID
LoadingElementDuration Loading元素动画显示的时长
UpdateTargetId 请求返回结果要插入的元素ID
Url Ajax表单提交的URL

上面的GetPeople视图Ajax form提交的URL是/People/GetPeopleData,如果用户禁止了java脚本,提交form返回的结果会只是GetPeopleData分部视图,我们可以直接在ajaxOptions指定ajax请求的URL来解决:

@using HelperMethods.Models
@model string
@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 1000,
        Confirm = "Do you wish to request new data?"
    };
}
<h2>Get People</h2>
<div id="loading" class="load" style="display:none">
    <p>Loading Data...</p>
</div>
<table>
    <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>
    <tbody id="tableBody">
        @Html.Action("GetPeopleData", new { selectedRole = Model })
    </tbody>
</table>
@using (Ajax.BeginForm(ajaxOpts))
{
    <div>
        @Html.DropDownList("selectedRole", new SelectList(
new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
        <button type="submit">Submit</button>
    </div>
}

生成的表单HTML:

...
<form action="/People/GetPeople"data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" data-ajax-url="/People/GetPeopleData"id="form0" method="post">
... 

这样表单提交的URL依然是/People/GetPeople,即使禁止了java脚本返回的仍然是GetPeople页面,ajax请求的URL通过data-ajax-url指定为/People/GetPeopleData。我们还设置 AjaxOptions.LoadingElementId为Loading,这是一个diplay:none风格的DIV元素,它只在AJAX异步请求时显示一秒钟(LoadingElementDuration = 1000)。AjaxOptions.Confirm= "Do you wish to request new data?" ,在每次Ajax请求时都会弹出网页Message对话框询问(对话框消息为这里设定的"Do you wish to request new data?")。

Ajax链接

上面的例子中我们使用表单提交数据,如果是使用链接做ajax异步请求可以这样操作:

...
<div>
@foreach (string role in Enum.GetNames(typeof(Role))) {
  <div class="ajaxLink">
  @Ajax.ActionLink(role, "GetPeopleData",
    new {selectedRole = role},
    new AjaxOptions {UpdateTargetId = "tableBody"})
  </div>
}
</div>
...

这里对role枚举中每个元素生成一个链接,生成的链接元素类似:

...
<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" href="/People/GetPeopleData?selectedRole=Guest">Guest</a>
... 

点击某个链接时ajax返回的HTML数据会用于替换tableBody元素,和使用表单提交ajax请求效果一样。同样如果禁用了java脚本,返回的结果会只是getpeopledata分部视图,我们可以这样改进:

<div>
@foreach (string role in Enum.GetNames(typeof(Role))) {
  <div class="ajaxLink">
  @Ajax.ActionLink(role, "GetPeople",
    new {selectedRole = role},
    new AjaxOptions { UpdateTargetId = "tableBody", Url = Url.Action("GetPeopleData", new {selectedRole = role})
    })
  </div>
}
</div> 

链接请求的地址是GetPeople,Ajax请求的URL则仅是GetPeopleData,请求的HTML结果作用于tablebody。

Ajax回调

AjaxOptions类暴露一组属性允许我们指定一个java脚本函数,在ajax请求周期中调用这些脚本函数:

属性 jQuery事件 说明
OnBegin beforeSend 在Ajax请求发送前调用
OnComplete complete 请求成功时调用
OnFailure error 请求失败时调用
OnSuccess success 无论请求成功与否都在请求完成时调用

结合回调函数我们可以对上面的例子进一步修改,首先修改控制器的GetPeopleData方法:

        public ActionResult GetPeopleData(string selectedRole = "All")
        {
            IEnumerable<Person> data = personData;
            if (selectedRole != "All")
            {
                Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
                data = personData.Where(p => p.Role == selected);
            }
            if (Request.IsAjaxRequest())
            {
                var formattedData = data.Select(p => new
                {
                    FirstName = p.FirstName,
                    LastName = p.LastName,
                    Role = Enum.GetName(typeof(Role), p.Role)
                });
                return Json(formattedData, JsonRequestBehavior.AllowGet);
            }
            else
            {
                return PartialView(data);
            }
        } 

我们使用Request.IsAjaxRequest判断请求是否来自于ajax,它的依据是浏览器在ajax请求时在头中会包含X-Requested-With=XMLHttpRequest。如果请求来自于ajax,控制器方法返回的是Json(data, JsonRequestBehavior.AllowGet)创建的JsonResult对象,默认JSON数据只在POST请求中发送,这里在第二个参数中指定JsonRequestBehavior.AllowGet允许在GET请求中使用JSON数据。MVC框架负责对formattedData做json封装,封装的格式由MVC尝试使用最适宜的方法确定,这里返回的JSON数据类似:

...
{"PersonId":0,"FirstName":"Adam","LastName":"Freeman",
"BirthDate":"\/Date(62135596800000)\/","HomeAddress":null,"IsApproved":false,"Role":0}
... 

视图中我们在AjaxOptions的OnSucess回调函数中处理返回的JSON数据:

@using HelperMethods.Models
@model string
@{
    ViewBag.Title = "GetPeople";
    AjaxOptions ajaxOpts = new AjaxOptions
    {
        //UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 1000,
        OnSuccess = "processData"
    };
}
<script type="text/javascript">
    function processData(data) {
        var target = $("#tableBody");
        target.empty();
        for (var i = 0; i < data.length; i++) {
            var person = data[i];
            target.append("<tr><td>" + person.FirstName + "</td><td>"
            + person.LastName + "</td><td>" + person.Role + "</td></tr>");
        }
    }
</script>
<h2>Get People</h2>
<div id="loading" class="load" style="display: none">
    <p>Loading Data...</p>
</div>
<table>
    <thead>
        <tr>
            <th>First</th>
            <th>Last</th>
            <th>Role</th>
        </tr>
    </thead>
    <tbody id="tableBody">
        @Html.Action("GetPeopleData", new { selectedRole = Model })
    </tbody>
</table>
@using (Ajax.BeginForm(ajaxOpts))
{
    <div>
        @Html.DropDownList("selectedRole", new SelectList(
new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
        <button type="submit">Submit</button>
    </div>
}

<div>
    @foreach (string role in Enum.GetNames(typeof(Role)))
    {
        <div class="ajaxLink">
            @Ajax.ActionLink(role, "GetPeople",
new { selectedRole = role },
new AjaxOptions
{
    Url = Url.Action("GetPeopleData", new { selectedRole = role }),
    OnSuccess = "processData"
})
        </div>
    }
</div>

脚本函数processData在AjaxOptions的OnSuccess回调时调用,它负责处理请求返回的JSON数据,从中分拆出各个Person对象,根据这些数据直接改写tableBody标签的内容,因此我们不再需要在AjaxOptions通过UpdateTargetId指定要替换内容的元素。

以上为对《Apress Pro ASP.NET MVC 4》第四版相关内容的总结,不详之处参见原版 http://www.apress.com/9781430242369

时间: 2024-10-12 04:16:59

ASP.NET MVC 4 (八) URL链接和Ajax帮助函数的相关文章

在ASP.NET MVC控制器中获取链接中的路由数据

在ASP.NET MVC中,在链接中附加路由数据有2种方式.一种是把路由数据放在匿名对象中传递: <a href="@Url.Action("GetRouteData","Home",new { ReturnUrl = Request.Url.PathAndQuery, x = 10})">走你</a> 一种是放在RouteValueDictionary对象中传递: <a href="@Url.Action

玩转Asp.net MVC 的八个扩展点

MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供的扩展点可以达到事半功倍的效果,另一方面Asp.net MVC优秀的设计和高质量的代码也值得我们去阅读和学习. 本文将介绍Asp.net MVC中常用的八个扩展点并举例说明. 一.ActionResult ActionResult代表了每个Action的返回结果.asp.net mvc提供了众多内置的ActionResult类型,如:ContentResult,ViewResult,JsonRe

ASP.NET MVC中获取URL地址参数的两种写法

一.url地址传参的第一种写法 1.通过mvc中默认的url地址书写格式:控制器/方法名/参数 2.实例:http://localhost:39270/RequestDemo/Index/88,默认参数名为id所以名称为id. 如果使用其他名称,后台是无法读取的会报错 二.url地址传参的第二种写法 1.使用?加参数名=参数值的写法,如果有多个参数使用&来连接 http://localhost:39270/RequestDemo/Index?id=88&name=%E5%BC%A0%E4%

ASP.NET MVC学习目录

一.ASP.NET MVC原理详解 1.了解MVC架构模式 3.学习ASP.NET MVC的必备语言知识 4.MVC中的razor语法详解 5.ASP.NET MVC路由系统机制详细讲解 6.ASP.NET MVC输出生成Url链接详解 7.自定义ASP.NET MVC路由系统截获MVC的路由请求 8.ASP.NET MVC使用Area区域,使用功能模块清晰明了 9.ASP.NET MVC的Controller介绍 10.ASP.NET MVC的Controller接收输入详解 11.ASP.N

ASP.NET MVC 5 Web编程2 -- URL映射(路由原理)

本章将讲述ASP.NET MVC5 的路由原理,即URL映射机制. 简单点就是解释:为什么MVC在浏览器输入地址就能访问到类(或类中的方法)?这是怎么做到的?我自己可以通过.NET写出一个自己的MVC框架吗? 答案是:可以. 模拟URL映射 先来看一个Demo,在传统的.NET WebForms项目中,实现URL的拦截. 打开VS2013,新建一个“ASP.NET Web窗体应用程序”项目,并取名为Demo4URLRouting. 为了方便测试,注释掉Default.aspx页面的内容和模板引用

ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL

ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL 引言--- 在现今搜索引擎制霸天下的时代,我们不得不做一些东西来讨好爬虫,进而提示网站的排名来博得一个看得过去的流量. URL重写与优化就是搜索引擎优化的手段之一. 假如某手机网站(基于ASP.NET MVC)分类页面URL是这样的, http://www.xxx.com/category/showcategory?categoryid=1000&view=list&orderby=price&p

How ASP.NET MVC Works?

一.ASP.NET + MVC IIS与ASP.NET管道 MVC.MVP以及Model2[上篇] MVC.MVP以及Model2[下篇] ASP.NET MVC是如何运行的[1]: 建立在“伪”MVC框架上的Web应用 ASP.NET MVC是如何运行的[2]: URL路由 ASP.NET MVC是如何运行的[3]: Controller的激活 ASP.NET MVC是如何运行的[4]: Action的执行 二.URL 路由 ASP.NET的路由系统:URL与物理文件的分离 ASP.NET的路

全网最全ASP.NET MVC 教程汇总

全网最全ASP.NET MVC 教程汇总 MVC架构已深得人心,微软也不甘落后,推出了Asp.net MVC.小编特意整理博客园乃至整个网络最具价值的MVC技术原创文章,为想要学习ASP.NET MVC技术的学习者提供一个整合学习入口.本文从Why,What,How三个角度整理MVC 的学习资源,让学习者第一时间找到最有价值的文章,获取最彻底的ASp.NET MVC 框架知识,Let’s go! 1. Why :为什么需要ASP.NET MVC 本章主要为大家汇总了为什么学习Asp.net MV

ASP.Net MVC开发基础学习笔记:三、Razor视图引擎、控制器与路由机制学习

一.天降神器“剃须刀” — Razor视图引擎 1.1 千呼万唤始出来的MVC3.0 在MVC3.0版本的时候,微软终于引入了第二种模板引擎:Razor.在这之前,我们一直在使用WebForm时代沿留下来的ASPX引擎或者第三方的NVelocity模板引擎. Razor在减少代码冗余.增强代码可读性和Visual Studio智能感知方面,都有着突出的优势.Razor一经推出就深受广大ASP.Net开发者的喜爱. 1.2 Razor的语法 (1)Razor文件类型:Razor支持两种文件类型,分