Ajax - ASP.NET MVC 4 系列

       ASP.NET MVC 框架中包含一组 Ajax 辅助方法,可以用来创建表单和指向控制器操作的链接,它们是异步的,且不用编写任何脚本代码来实现程序的异步性,但需要引入脚本文件 jquery.unobtrusive-ajax.js,MVC 4 应用程序默认在 _Layout 视图中包含这个脚本:

      

       当然,也可以去除它,而在需要的页面上手动引入:

      

Ajax 的 ActionLink 方法

       在 Razor 视图中,可通过 Ajax 属性方法,该方法可创建一个具有异步行为的锚标签:

<div id="dailydeal">
    <!--
        参数1:链接文本
        参数2:要异步调用的操作名称
        参数3:AjaxOptions 对象
    -->
    @Ajax.ActionLink("Click here to see today‘s special!",
        "DailyDeal",
        new AjaxOptions
        {
            UpdateTargetId = "dailydeal",
            InsertionMode = InsertionMode.Replace,
            HttpMethod = "GET"
        }
    )
</div>

       AjaxOptions 参数指定了发送请求和处理服务器返回的结果的方式,该参数还包括处理错误、显示和加载元素、显示确认对话框等的选项:

      

       服务器端需要有一些响应的代码,此例中为 DailyDeal 操作,这里仅返回一个简单的系统时间字符串:

public string DailyDeal()
{
    return DateTime.Now.ToString();
}

      

HTML 5 特性

       Ajax.ActionLink 生成的内容能够获取服务器的响应,并可以直接把新内容移植到页面中,这是如何发生的呢?

       如果查看该方法渲染的标记,就会看到如下代码:

<a data-ajax="true"
   data-ajax-method="GET"
   data-ajax-mode="replace"
   data-ajax-update="#dailydeal"
   href="/Home/DailyDeal">
    Click here to see today's special!
</a>

       仔细看,ActionLink 方法中指定的所有设置都被编码成了 HTML 特性,并且大多数特性都有 data-前缀,通常称为 data-特性。

       HTML 5 规范为私有应用程序保留了 data-特性,Web 浏览器不会尝试解释它的内容,因此可以放心的把数据交给它,这些数据不会影响页面的显示或渲染。添加 jquery.unobtrusive-ajax.js 文件的目的是查找特定的 data-特性,然后操纵元素使其表现出不同行为。本例中,jQuery 查找了 a[data-ajax]=true 的所有锚标记,脚本识别了该异步元素,它自然就可以读取该元素的其他设置(像替换模式、更新目标、HTTP 方法),还能通过使用 jQuery 连接事件和发送请求来修改该元素的行为。

Ajax 表单

       如果要在页面增加一个搜索功能,因为需要由用户的输入而做出相应的反馈,所以必须在页面上放置一个 form 表单,这里放一个异步表单:

@using (Ajax.BeginForm("ArtistSearch", "Home",
    new AjaxOptions
    {
        InsertionMode = InsertionMode.Replace,
        HttpMethod = "GET",
        OnFailure = "searchFailed",
        LoadingElementId = "ajax-loader",
        UpdateTargetId = "searchResults"
    }
))
{
    <input type="text" name="q" />
    <input type="submit" value="search" />
    <img id="ajax-loader" src="@~Content/Images/ajax-loader.gif" style="display:none" />
}

       当用户进行搜索时,浏览器会向 Home 控制器的 ArtistSearch 操作发送异步 GET 请求; 当执行异步请求时,客户端框架会显示 LoadingElementId 指定的元素,通常这个元素会出现一个具有动画效果的图片来告知用户后台正在进行一些处理;如果服务器代码返回一个错误,就意味着 Ajax 辅助方法执行失败,OnFailure 选项会触发预先设置的 js 函数,至少可以提示一个错误信息,让用户知道我们已经尽力了。

function searchFailed() {
    $("#searchResults").html("Sorry, there was a problem with the search.");
}

客户端验证

       对于数据注解特性来说,ASP.NET MVC 框架的客户端验证是默认开启的。下面介绍 Album 类的 Title 和 Price 属性:

[Required(ErrorMessage = "An Album Title is required")]
[StringLength(160)]
public string Title { get; set; }
 
[Required(ErrorMessage = "Price is required")]
[Range(0.01, 100.00, ErrorMessage = "Price must be between 0.01 and 100.00")]
public decimal Price { get; set; }

       ASP.NET MVC 模型绑定器在设置这些属性时会执行服务器端验证,但同时,这些内置的特性也会触发客户端验证,客户端验证依赖于 jQuery 验证插件。

jQuery 验证

       默认情况下,非侵入式 JavaScript 和客户端验证在 ASP.NET MVC 中是启用的,但通过 web.config 文件中的设置也可以改变这些行为:

      

       如果需要实现客户端验证,那么需要一对脚本标签:

      

       第一个 script 是验证插件,jQuery 验证实现了挂接到事件需要的所有逻辑(像提交和焦点事件),此外,还要执行客户端验证规则,该插件提供了丰富的默认验证规则集。

       第二个 script 用于 jQuery 验证的 Microsoft 非侵入式适配器。这段脚本中的代码用来获取 ASP.NET MVC 框架发出的元数据,并将这些元数据转换成 jQuery 验证能够理解的数据!

       那么,这些元数据从何而来?先看下面的 view 片段:

<p>
    @Html.LabelFor(model => model.Title)
    @Html.TextBoxFor(model => model.Title)
    @Html.ValidationMessageFor(model => model.Title)
</p>
<p>
    @Html.LabelFor(model => model.Price)
    @Html.TextBoxFor(model => model.Price)
    @Html.ValidationMessageFor(model => model.Price)
</p>

       这里,辅助方法 TextBoxFor 是关键,它为基于元数据的模型构建输入元素,当它看到验证元数据(属性上的数据注解)时,会将这些元数据放入到渲染的 HTML 中:

<p>
    <label for="Title">Title</label>
    <input data-val="true" data-val-length="字段 Title 必须是最大长度为 160 的字符串。" data-val-length-max="160" data-val-required="An Album Title is required" id="Title" name="Title" type="text" value="" />
    <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
</p>
<p>
    <label for="Price">Price</label>
    <input data-val="true" data-val-number="字段 Price 必须是一个数字。" data-val-range="Price must be between 0.01 and 100.00" data-val-range-max="100" data-val-range-min="0.01" data-val-required="Price is required" id="Price" name="Price" type="text" value="" />
    <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
</p>

       再次看到了 data-特性,上述代码中,jquery.validate.unobtrusive 脚本负责使用这个元数据(以 data-val="true"开头)查找元素,并结合 jQuery 验证插件来执行元数据内的验证规则!jQuery 验证可运行每个击键和焦点事件上的规则,给用户提供关于错误值的及时反馈,当出现错误时,验证插件也能阻止表单提交,这也意味着不必在服务器上处理注定要失败的请求。

自定义验证

       之前的篇章中,曾经写过自定义验证特性 MaxWordsAttribute 来验证一个字符串中的单词数量:

public class MaxWordsAttribute : ValidationAttribute
{
    private readonly int _maxWords;
    public MaxWordsAttribute(int maxWords) : base("Too many words in {0}")
    {
        this._maxWords = maxWords;
    }
 
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            var valueString = value.ToString();
            if (valueString.Split(‘ ‘).Length > this._maxWords)
            {
                return new ValidationResult("Too many words!");
            }                
        }
        return ValidationResult.Success;
    }
}
 
// 可以启用这个自定义特性
[Required(ErrorMessage = "An Album Title is required")]
[StringLength(160)]
[OAuthMVC.Filters.MaxWords(10)]
public string Title { get; set; }

       1. 现在的问题是,这个自定义特性只支持服务器端的验证,而为了支持客户端验证,需要让特性实现接口 System.Web.Mvc.IClientValidatable,IClientValidatable 接口定义了单个方法 GetClientValidationRules,当 ASP.NET MVC 框架使用这个接口查找验证对象时,它会调用 GetClientValidationRules 方法来检索 ModelClientValidationRule 对象序列,这些对象携带有框架发送给客户端的元数据和规则,实现如下:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
    var rule = new ModelClientValidationRule();
    rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
    rule.ValidationParameters.Add("wordcount", _maxWords);
    rule.ValidationType = "maxwords";
    yield return rule;
}

       要实现在客户端执行验证,需要提供:验证失败时的提示消息、允许的单词数的范围、一段用来计算单词数量的 JavaScript 代码标识。这些信息就是代码放进返回规则中的内容(如需在客户端触发多种类型的验证,代码可以返回多个规则)。ASP.NET MVC 框架在客户端上将这些返回的规则序列化为 data-特性:

<input data-val="true"
       data-val-length="字段 Title 必须是最大长度为 160 的字符串。"
       data-val-length-max="160"
       data-val-maxwords="Too many words in Title"
       data-val-maxwords-wordcount="10"
       data-val-required="An Album Title is required" id="Title" name="Title" type="text" value="" />

       验证类型(rule.ValidationType)和所有验证参数的名称(rule.ValidationParameters)必须都是小写,因为它们的值必须能够作为合法的 HTML 特性标识符使用。

       2. 先前说过,客户端也需要一段计算单词数量的 JS 代码标识。幸运的是,我们没必要在客户端编写代码来从 data-特性 中挖掘元数据值。为了执行验证工作,需要以下两段脚本代码:

  • 适配器:适配器和非侵入式 MVC 扩展一道识别需要的元数据,然后非侵入式扩展帮助从 data-特性 中检索值,并且把数据转换成 jQuery 能理解的格式。
  • 验证规则:在 jQuery 用于中被称为验证器。

       这两段代码都在同一个文件中,假设是 MusicScripts.js 文件,要确保 MusicScripts.js 出现在验证脚本之后:

      

       首先要编写的代码是适配器。MVC 框架的非侵入式验证扩展存储了 jQuery.validator.unobtrusive.adapters 对象中的所有适配器,这些适配器对象公开了一个 API,可以用来添加新的适配器,如下表:


名  称


描  述

addBool 为“启用”或“禁止”的验证规则创建适配器,不需要额外参数。
addSingleVal 为需要从元数据中检索唯一参数值的验证规则创建适配器。
addMinMax 创建一个映射到验证规则的适配器,一个检查最小值,一个检查最大值,且这两个规则中至少有一个要依靠得到的数据运行。
Add 创建一个不适合前面类别的适配器,因为它需要额外参数或额外的设置代码

       对于最大单词数的情形,可使用 addSingleVal 或 addMinMax (或 Add,因为它适用于任何场合),由于不需要检查单词的最小数量,因此,选择第一个 addSingleVal:

// 参数一:适配器名称,必须与服务器端设置的 ValidationType 值匹配
// 参数二:要从元数据中检索的参数的名称,它匹配服务器的 ValidationParameters 集合的参数名称
$.validator.unobtrusive.adapters.addSingleVal("maxwords", "wordcount");

       适配器相对而言比较简单,主要目标是识别非侵入式扩展要定位的元数据。有了适配器,现在就可以编写验证器。所有验证器都在 jQuery.validator 对象中,与 adapters 对象类似,validator 对象也有一个 API 函数,可用来添加新验证器,该函数的名称是:addMethod:

// 参数一:验证器名称,默认情况下,要匹配适配器的名称,而适配器的名称又要匹配服务器端的 ValidationType 值
// 参数二:当验证发生时被调用
// value:用户输入的值,如专辑的名称
// element:输入元素,其中也包含了要验证的值(在 value 本身没有提供足够信息的情况下使用)
// 第三个函数参数:一个所有验证参数的数组,这个示例中包含了单一验证参数(即最大的单词数量)
$.validator.addMethod("maxwords", function (value, element, maxwords) {
    if (value) {
        if (value.split(‘ ‘).length > maxwords) {
            return false;
        }
    }
    return true;
});

JSON 劫持

       默认情况下,ASP.NET MVC 框架不允许使用 JSON 负载响应 HTTP GET 请求。如果为了响应 GET 请求,需要发送 JSON 格式的数据,就需要使用 JsonRequestBehavior.AllowGet 作为 Json 方法的第二个参数显式的来支持这一操作,例如:

public ActionResult DailyDeal()
{
    var album = new Models.Album();
    return Json(album, JsonRequestBehavior.AllowGet);
}

       然而,这样就给了恶意用户可乘之机,他们可以通过知名的 JSON 劫持进程来获得对 JSON 负载的访问权,因此,不要在 GET 请求中使用 JSON 格式返回敏感信息。请参看这个例子:http://haacked.com/archive/2009/06/25/json-hijacking.aspx

修改搜索表单

       尽管 Ajax 辅助方法提供了大量功能,但现在我们删除这些辅助方法,从头开始。jQuery 提供了从服务器检索数据的各种 API,首先修改表单使其直接使用 jQuery 而不使用 Ajax 辅助方法,修改后的 Index.cshtml 视图如下:

<form id="artistSearch" method="get" action="@Url.Action("ArtistSearch","Home")">
    <input type="text" name="q" data-autocomplate-source="@Url.Action("QuickSearch","Home")" />
    <input type="submit" value="search" />
    <img id="ajax-loader" src="@~Content/Images/ajax-loader.gif" style="display:none" />
</form>

       显而易见,如果不使用 Ajax 辅助方法,我们就需要自己编写 JS 代码来向服务器请求 HTML:

$("#artistSearch").submit(function (event) {
    // 阻止触发默认事件,这里可以阻止表单直接提交到服务器
    event.preventDefault();
 
    var form = $(this);
    $.getJSON(form.attr("action"), form.serialize(), function (data) {
        // data 是服务器返回的 JSON 数据,这里可以做任何事,包括渲染客户端模板(如 Mustache 等)
    });
});

      form.attr("action") 可以使用 action 的特性值得到正确的 URL, form.serialize() 将表单内部所有输入值连接成一个字符串来构建数据,这里的例子是“q=xxx”,发出一个请求后,将得到的 JSON 响应反序列化为一个对象,然后作为参数来调用一个回调函数,回调函数内部可以做你想做的事。

使用 jQuery.ajax 获得最大灵活性

       当要实现对 Ajax 请求的完全控制时,可以使用 jQuery.ajax 方法。该方法只使用一个参数,但可以指定 HTTP 动词(如GET、POST、DELETE、PUT等)、超时、错误处理程序等。所有其它的异步通信方法最终都调用了 ajax 方法!如:

$("#artistSearch").submit(function (event) {
    // 阻止触发默认事件,这里可以阻止表单直接提交到服务器
    event.preventDefault();
 
    var form = $(this);
    $.ajax({
        url: form.attr("action"),
        data: form.serialize(),
        beforeSend: function () {
            $("#ajax-loader").show();
        },
        complete: function () {
            $("#ajax-loader").hide();
        },
        error: searchResults,
        success: function (data) {
            var html = Mustache.to_html($("#artistTemplate").html(), { artist: data });
            $("#searchResults").empty().append(html);
        }
    });
});

       调用 ajax 方法是繁琐的,因为需要自定义很多设置。url 和 data 属性就像是传递给 load 和 getJSON 方法的参数;回调期间又分别显示和隐藏了 gif 动画;即便调用服务器导致失败,jQuery 都将调用 complete 指定的回调函数;error 和 success 中只会有一个可以调用成功。

时间: 2024-11-10 06:58:53

Ajax - ASP.NET MVC 4 系列的相关文章

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

ASP.NET MVC学习系列(二)-WebAPI请求(转)

转自:http://www.cnblogs.com/babycool/p/3922738.html 继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax

ASP.NET MVC学习系列(一)-WebAPI初探

由于即将要接手的新项目计划用ASP.NET MVC3来开发,所以最近一段时间一直在看相关的书或文章.因为之前在大学里也曾学习过MVC2开发,也做过几个简单的MVC2的小型测试项目,不过在后来工作以后主要还是开发WebForm的项目,所以MVC的东西也就逐渐的淡忘了. 经过这一段时间的系统学习,真的觉得MVC3相比于之前的MVC2还有WebForm来说,确实有一种让人欲罢不能爽歪歪的感觉.特别是Razor语法.Linq表达式等的结合运用. 为了将学习过程中遇到的一些值得留意的问题和知识点进行一个很

Razor 视图引擎 &ndash; ASP.NET MVC 4 系列

       Razor 视图引擎是 ASP.NET MVC 3 开始扩展的内容,并且也是默认视图引擎.        Razor 通过理解标记的结构来实现代码和标记之间尽可能顺畅的转换.下面的例子演示了一个包含少量视图逻辑的简单 Razor 视图: @{ // this is a block of code. For demonstration purposes, // we'll create a "model" inline. var items = new string[] {

ASP.NET MVC 入门系列教程

ASP.NET MVC 入门1.简介 ASP.NET MVC 入门2.项目的目录结构与核心的DLL ASP.NET MVC 入门3.Routing ASP.NET MVC 入门4.Controller与Action ASP.NET MVC 入门5.View与ViewData ASP.NET MVC 入门6.TempData ASP.NET MVC 入门7.Hellper与数据的提交与绑定 ASP.NET MVC 入门8.ModelState与数据验证 ASP.NET MVC 入门9.Action

数据注解和验证 &ndash; ASP.NET MVC 4 系列

       不仅在客户端浏览器中需要执行验证逻辑,在服务器端也需要执行.客户端验证能即时给出一个错误反馈(阻止请求发送至服务器),是时下 Web 应用程序所期望的特性.服务器端验证,主要是因为来自网络的信息都是不可信任的.        当在 ASP.NET MVC 设计模式上下文中谈论验证时,主要关注的是验证模型的值.ASP.NET MVC 验证特性可以帮助我们验证模型值,且这样验证特性是可扩展的,所以我们可以采用任意想要的方式构建验证模式,默认方法是一种声明式验证,即数据注解特性.    

控制器(Controller) &ndash; ASP.NET MVC 4 系列

       创建一个 ASP.NET MVC 4 Web Application 项目,将程序命名为 MvcMusicStore,如下图: 控制器        MVC 模式中,控制器主要负责响应用户的输入.并且在响应时修改模型.提供相关视图的输出数据.        请求的 URL 首先被路由机制截获,以决定实例化哪一个控制器,调用哪个操作方法,并未该方法提供需要的参数.然后,控制器的方法决定使用哪个视图,并对该视图进行渲染.        添加一个新的 Empty 控制器,命名为 Stor

扩展 ASP.NET MVC 模型扩展 &ndash; ASP.NET MVC 4 系列

       大部分人不能将核心运行时(System.Web 中的类)和 ASP.NET Web Forms 应用程序平台(System.Web.UI 中的类)区分开来.        ASP.NET 开发团队在简单的核心运行时抽象之上创建了复杂的 Web Form 抽象和 ASP.NET MVC.正因为 ASP.NET MVC 框架建立在公共抽象之上,所以 ASP.NET MVC 框架能实现的任何功能,任何人也都可以实现.ASP.NET MVC 框架本身也由若干层抽象组成,从而使得开发人员能够

Web 应用程序中的安全向量 &ndash; ASP.NET MVC 4 系列

       Web 程序运行在标准的.基于文本的协议(HTTP 和 HTML)之上,所以特别容易受到自动攻击的伤害.本章主要介绍黑客如何滥用应用程序,以及针对这些问题的应对措施.   威胁:跨站脚本攻击(XSS)        XSS 攻击在 Web安全威胁上排名第一,然而遗憾的是,导致 XSS 猖獗的主要原因是开发人员不熟悉这种攻击.可以使用 2 种方法实现 XSS: 被动注入(Passive Injection):通过用户将恶意的脚本命令输入到网站中,而这些网站又能接收"不干净"