ASP.NET07

本文总阅读量:
  1. 1. XmlHttpRequest对象
    1. 1.1. AJAX优点
    2. 1.2. 异步请求基本步骤
    3. 1.3. readyState属性
    4. 1.4. XMLHttpRequest对象属性
    5. 1.5. XMLHttpRequest对象常用方法
    6. 1.6. Ajax使用注意
    7. 1.7. 演示
  2. 2. 基于AjaxHelper的Ajax
    1. 2.1. 导入js
    2. 2.2. Ajax.ActionLink():
    3. 2.3. 实际应用:
      1. 2.3.1. 使用Ajax.ActionLink请求返回值为 Json格式的Controller方法
      2. 2.3.2. 使用Ajax.ActionLink 请求返回值为PartialView格式的Controller方法
    4. 2.4. Ajax.BeginForm
  3. 3. 基于JQuery的Ajax
    1. 3.1. 使用JQuery的Ajax请求返回值为 Json格式的Controller方法
    2. 3.2. 使用JQuery的Ajax 请求返回值为PartialView格式的Controller方法
  4. 4. 如何提高Ajax性能

AJAX:”Asynchronous JavaScript and XML”
中文意思:异步JavaScript和XML。
指一种创建交互式网页应用的网页开发技术。

XmlHttpRequest对象

AJAX优点

Ajax在本质上是一个浏览器端的技术
Ajax技术之主要目的在于局部交换客户端及服务器间之数据
这个技术的主角XMLHttpRequest 的最主要特点,在于能够不用重新载入整个版面来更新资料,也就是所谓的Refresh without Reload(轻刷新)
与服务器之间的沟通,完全是透过Javascript 来实行
使用XMLHttpRequest 本身传送的数据量很小,所以反应会更快,也就让网络程式更像一个桌面应用程序
AJAX 就是运用Javascript 在后台悄悄帮你去跟服务器要资料,最后再由Javascript 或DOM 来帮你呈现结果,因为所有动作都是由Javascript 代劳,所以省去了网页重载的麻烦,使用者也感受不到等待的痛苦

异步请求基本步骤

使用XMLHttpRequest对象

按照下面模式,可以同步地XMLHttpRequest对象:

创建对象; - new (叫助手过来)
创建请求; - open (告诉他要去做的事情)
发送请求; - send (去吧)

readyState属性

readyState属性指出了XMLHttpRequest对象在发送/接收数据过程中所处的几个状态。XMLHttpRequest对象会经历5种不同的状态。

0:未初始化。new完后;
1:已打开。对象已经创建并初始化,但还未调用send方法
2:已发送。已经调用send 方法,但该对象正在等待状态码和头的返回;
3:正在接收。已经接收了部分数据,但还不能使用该对象的属性和方法,因为状态和响应头不完整;
4:已加载。所有数据接收完毕

XMLHttpRequest对象属性

一、onreadystatechange属性,设置回调函数。
二、readyState属性,获取当前XMLHttpRequest对象执行的状态:

1> 0表示以创建XMLHttpRequest对象,但是还没有初始化,即没有调用open()方法设置XMLHttpRequest对象。
2>1表示创建了XMLHttpRequest对象,并且调用了open()方法进行初始化,但是还没有调用send()方法。
3>3表示浏览器正在接受服务器的响应数据。
4>所有数据已经被接受完毕。

三、status属性,服务器返回的http状态码。(>=200 and <300、304未修改,读取缓存。都表示成功)
四、statusText属性,服务器返回的状态码对应的友好的文字说明,比如200对应的OK.
五、responseText属性,以字符串方式获取服务器对客户端的响应。
六、responseXml属性,当请求的是一个xml文件时,或者响应头中Content-Type为:text/xml或application/xml时,返回一个XmlDocument对象(Dom节点对象),支持标准的dom的成员,比如:childNodes、documentElement、firstChild、lastChild、nextSibling、nodeName、nodeType、nodeValue、parentNode、doctype等。

XMLHttpRequest对象常用方法

一、open(“get”,”url”,true)初始化,如果第三个参数为false,则js等待请求完毕后才会继续执行。
二、setRequestHeader(“”,””)增加http请求头信息。在open()之后,send()之前调用。
三、send(null);发送请求。send()方法的参数表示为在请求报文体中发送的数据内容。为了最大化的浏览器兼容问题,如果没有请求报文体就传递null。get请求没有请求报文体,所以一般为null。使用post请求时才需要设置报文体。
四、getResponseHeader(“Content-Type”),根据响应的报文头获得报文内容。
五、getAllResponseHeaders();获取所有的响应报文头内容。
六、abort();取消当前的http请求,取消之后如果要重新发起请求,建议重新创建一个XMLHttpRequest对象。

Ajax使用注意

  1. xhr只能向同一个域中的相同端口号、相同协议的url发起请求,不能跨域,否则会引起错误。
  2. 为了浏览器兼容,get请求时最好为send()传递null参数。
  3. 在创建了xhr对象后立刻设置onreadystatechange事件,这样就能监视到所有的状态。如果不需要监视其他状态只监视readyState==4的状态则可以在send()之前设置。
  4. get请求时,请求中的QueryString的参数名称与参数值最好使用encodeURIComponent()进行编码。否则在某些浏览器下无法获取该值,比如IE.
  5. post请求时,为了像表单那样提交数据需要设置请求的Content-Type为:application/x-www-form-urlencoded。send(“键=值&键=值”)
  6. 解析json格式时eval(“(“+json+”)”)。但有安全性问题

演示

cshtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}

<button id="btn1">click(get)</button>
<div id="dv1">Time</div>
<button id="btn2">click(post)</button>
<div id="dv2"></div>

@section scripts{
<script>
//Get
document.getElementById("btn1").onclick=function (){
var xhr;
if (XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
xhr.open("get","@Url.Action("GetTime")");
xhr.onreadystatechange=function () {
if(xhr.readyState == 4){
document.getElementById("dv1").innerText=xhr.responseText;
}
}
xhr.send();
}

//Post
document.getElementById("btn2").onclick=function (){
var xhr;
if (XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
xhr.open("post", "@Url.Action("GetName")");
//加头
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange=function () {
if(xhr.readyState == 4){
document.getElementById("dv2").innerText=xhr.responseText;
}
}
//send里面发送数据
xhr.send("name=luox78");
}
</script>
}

controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//get
public ActionResult AjaxTest()
{
return View();
}
public string GetTime()
{
return DateTime.Now.ToString();
}
[HttpPost]
public string GetName(string name)
{
return name;
}

基于AjaxHelper的Ajax

MVC框架本身提供了AjaxHelper类用于Ajax异步请求,所以如果你想省事,就用这种方式吧~

AjaxHelper帮助器方法:

Helper method Description
Ajax.ActionLink Creates a hyperlink to a controller action that fires an Ajax request when clicked
Ajax.RouteLink Similar to Ajax.ActionLink, but generates a link to a particular route instead of a named controller action
Ajax.BeginForm Creates a form element that submits its data to a particular controller action using Ajax
Ajax.BeginRouteForm Similar to Ajax.BeginForm, but creates a form that sub- mits its data to a particular route instead of a named control- ler action
Ajax.GlobalizationScript Creates an HTML script element that references a script that contains culture information
Ajax.JavaScriptStringEncode Encodes a string to make sure that it can safely be used inside JavaScript

上面的方法貌似很多,但是实际开发中用到的就两个帮助器方法而已:

Ajax.ActionLink()和Ajax.BeginForm()

这里有个问题:怎样让项目知道我们用的是MVC自带的Ajax呢?

导入js

A、在Web.config里边配置:

1
<add key="UnobtrusiveJavaScriptEnabled" value="true" />

B、在页面中引用下面的js类库即可:

1
2
3
@section scripts{
<script type="text/javascript" src=" @Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script>
}

一般更为常见的是在布局页/Views/Shared/_Layout.cshtml 中引入,例如:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
</head>
<body>
@RenderBody()
</body>
</html>

复制代码

  向客户端输出一个链接地址,当单击这个链接时可以Ajax调用Controller中的方法,Ajax.ActionLink()方法有许多重载,下面是其重载之一:

  public static string ActionLink(this AjaxHelper ajaxHelper, string linkText, string actionName, object routeValues, AjaxOptions ajaxOptions);

  linkText:是显示在客户端的文本

  actionName:是Action的名字,默认情况下我们会使用当前的Controller。

  routeValues:将传入到Controller中方法的参数

  ajaxOptions:配置Ajax的一些选项

Confirm 获取或设置提交请求之前,显示在确认窗口中的消息。
HttpMethod 获取或设置 HTTP 请求方法(“Get”或“Post”)。
InsertionMode 获取或设置指定如何将响应插入目标 DOM 元素的模式。
LoadingElementId 获取或设置加载 Ajax 函数时要显示的 HTML 元素的 id 特性。
OnBegin 获取或设置更新页面之前,恰好调用的 JavaScript 函数的名称。
OnComplete 获取或设置实例化响应数据之后但更新页面之前,要调用的 JavaScript 函数。
OnFailure 获取或设置页面更新失败时,要调用的 JavaScript 函数。
OnSuccess 获取或设置成功更新页面之后,要调用的 JavaScript 函数。
UpdateTargetId 获取或设置要使用服务器响应来更新的 DOM 元素的 ID。
Url 获取或设置要向其发送请求的 URL。

备注:

  • OnComplete和OnSuccess的区别:OnComplete是获取了Http请求时引发的,此时页面还没有进行更新,OnSuccess是在页面已经更新后引发的。
  • 当加载数据须要花较长时候,为了避免假死状况,该当给用户一个反馈信息,如“正在加载…”字样。在 MVC 的 Unobtrusive Ajax 中经用AjaxOptions选项的 LoadingElementId 和 LoadingElementDuration 两个属性可轻松做到这一点,例如下面的设置:

复制代码

1
2
3
4
5
6
AjaxOptions ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody"
Url = Url.Action("GetPeopleData"),
LoadingElementId = "loading"
LoadingElementDuration = 1000
};

复制代码

  • 对于URL,如果我们设置如下:
1
2
3
4
AjaxOptions ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody"
Url = Url.Action("GetPeopleData"
};

然后查看它生成的 form 属性:

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

它生成了两个 Url,分别为 action 属性 和 data-ajax-url 属性的值,前者是 Ajax.BeginForm() 办法按照当前 controller 和 action 名称生成的,后者是 AjaxOptions 的 Url 属性生成的。当浏览器没有禁用 JavaScript 时,Unobtrusive Ajax JS库会获取 data-ajax-url 属性的值作为 Url 产生 ajax 恳求。当浏览器禁用了 JavaScript 时,天然 action 属性的值决定了默示提交的 Url,自然访问该页面。固然局部未能刷新,但不会让用户体验很差。


使用Html.ActionLink方法的一个栗子:

1
2
@Ajax.ActionLink("点击我", "getEntry", new { id = item.Id }, new AjaxOptions 
{ HttpMethod = "Post", UpdateTargetId = "detailsID", InsertionMode = InsertionMode.Replace })

说明:“点击我”是生产的超链接文字;“getEntry”是当前控制器的Action方法;id = item.Id是向Action方法传递的参数;HttpMethod = “Post”, 说明Ajax请求是post方式的;UpdateTargetId = “detailsID”说明了要更新的html块的Id标记元素;InsertionMode = InsertionMode.Replace说明是替换ID为detailsID的元素里边的内容。

实际应用:

使用Ajax.ActionLink请求返回值为 Json格式的Controller方法

在Index.cshtml中使用ActionLink,如下:

1
2
@Ajax.ActionLink("点击我", "JsonDetails", new { id = item.Id }, 
new AjaxOptions { HttpMethod = "Post", InsertionMode = InsertionMode.Replace, OnSuccess = "Show" })

相应的Controller:

1
2
3
4
5
public ActionResult JsonDetails(int id = 0)
{
GuestbookEntry entry = _db.Entries.First(c => c.Id == id);
return Json(entry, JsonRequestBehavior.AllowGet);
}

同时需要在Index.cshtml中添加请求成功的相应js函数Show,以便更新ID属性为detailsID的DIV内容:

1
2
3
4
5
<script type="text/javascript">
function Show(data) {
$("#detailsID").html("姓名:" + data.Name + " 消息:" + data.Message);
}
</script>

在Index.cshtml中

1
2
@Ajax.ActionLink("AjaxPartialView", "Details", new { id = item.Id }, 
new AjaxOptions { HttpMethod = "Get", UpdateTargetId = "detailsID" })

相应的Controller:

复制代码

1
2
3
4
5
6
7
8
9
public ActionResult Details(int id = 0)
{
GuestbookEntry entry = _db.Entries.First(c => c.Id == id);
if (Request.IsAjaxRequest())
{
return PartialView(entry);
}
return View(entry);
}

复制代码

在这里我们使用Request.IsAjaxRequest()来判断是否为Ajax请求,如果是则返回PartialView,否则返回View。最后,返回的内容会直接更新到ID属性为detailsID的DIV中。

Ajax.BeginForm

这个方法用于异步提交表单,比如一个新增信息的页面Create.cshtml,下面的代码会使表单以Ajax方式提交

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@model MvcApplication5.Models.GuestbookEntry
<script type="text/javascript" src=" @Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script>
<script type="text/javascript">
function success(data) {
alert(data);
}
</script>
@{
ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Ajax.BeginForm(new AjaxOptions {
HttpMethod="Post",
OnSuccess = "success"
}))
{
@Html.ValidationSummary(true)

<fieldset>
<legend>GuestbookEntry</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Message)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Message)
@Html.ValidationMessageFor(model => model.Message)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}

复制代码

控制器的代码如下:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[HttpPost]
public ActionResult Create(GuestbookEntry entry)
{
if (ModelState.IsValid)
{
entry.DateAdded = DateTime.Now;
_db.Entries.Add(entry);
_db.SaveChanges();
return Content("New Entry successfully added.");
}
else {
return View();
}
}

复制代码

注:

貌似上面的Ajax方法很方便,但是它的工作原理可能大家不是很清楚,这里就大概说一下吧~

当调用 Ajax.BeginForm 方法后,经由选项 AjaxOptions 对象设置的属性将会被转化成 form 表单的属性,这些属性以 data-ajax 开首,如本示例生成的 form 表单:

1
<form action="/GuestBook/Create" data-ajax="true" data-ajax-mode="replace" data-ajax-="#tableBody" id="form0" method="post">

当 Create.cshtml 视图加载完成并浮现 Html 页面时,jquery.unobtrusive-ajax.js 库会寻找所有 data-ajax == true的元素,然后按照其它以 data-ajax 开头的属性值,jQuery 库中的函数将知道如何去执行 Ajax 请求。

基于JQuery的Ajax

使用JQuery的Ajax请求返回值为 Json格式的Controller方法

原理就是用JQuery的Ajax方法请求Action方法,返回值设为JSON,然后对JSON数据进行处理,例如用js函数进行处理

举个栗子:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<script type="text/javascript" language="javascript">
$(function(){
GetRoomInfoList();
});
function GetRoomInfoList() {
showDivLoading();//异步加载数据时的浮层
$.ajax({
type: "Post",
url: "@Url.Content("~/Room/GetRoomInfoShipId")",//异步请求的URL,就是Room控制器方法GetRoomInfoShipId(long shipId)
dataType: "json",//要求返回数据为JSON格式
data:{shipId:$("#ShipIdForSearch").val()},//异步请求的参数
success: function(data){
$("#RoomInfoListTable").empty(); //清空里面的所有内容
$.each(data, function(i, item){ //用js拼字符串处理数据,这里是显示所有房型列表信息

var str="<tr>";
str+=" <td>";
str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">";
str+=item.BaseRoomId;
str+=" </span>"
str+=" </td>";
str+=" <td>";
str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">";
str+=item.ShipId;
str+=" </span>"
str+=" </td>";
str+=" <td>";
str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">";
str+=item.RoomType;
str+=" </span>"
str+=" </td>";
str+=" <td>";
str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">";
str+=item.RoomName;
str+=" </span>"
str+=" </td>";
str+="</tr>";
$("#RoomInfoListTable").append(str);
});
}
});

}

复制代码

使用JQuery的Ajax 请求返回值为PartialView格式的Controller方法

假设有这样的一个Model:

复制代码

1
2
3
4
5
6
7
8
namespace MvcApplication1.Models
{
public class Team
{
public string Preletter { get; set; }
public string Name { get; set; }
}
}

复制代码

通过JQuery异步加载分部视图,Home/Index.cshtml:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<div>
<a href="#" id="a">通过jQuery异步</a> <br/>
</div>
<div id="result">
</div>
@section scripts
{
<script type="text/javascript">
$(function() {
$('#a').click(function() {
$.ajax({
url: '@Url.Action("Index","Home")',
data: { pre: 'B' },
type: 'POST',
success: function(data) {


$('#result').empty().append(data);


}
});

return false;
});
});
</script>
}

复制代码

HomeController控制器中:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string pre)
{
var result = GetAllTeams().Where(t => t.Preletter == pre).ToList();
ViewBag.msg = "通过jQuery异步方式到达这里~~";
return PartialView("TeamY", result);
}
private List<Team> GetAllTeams()
{
return new List<Team>()
{
new Team(){Name = "巴西队", Preletter = "B"},
new Team(){Name = "克罗地亚队", Preletter = "K"},
new Team(){Name = "巴拉圭", Preletter = "B"},
new Team(){Name = "韩国", Preletter = "K"}
};
}
}
}

复制代码

分部视图TeamY.cshtml:

复制代码

1
2
3
4
5
6
7
8
9
10
11
@model IEnumerable<MvcApplication1.Models.Team> 
@{
var result = string.Empty;
foreach (var item in Model)
{
result += item.Name + ",";
}
}
@ViewBag.msg.ToString()
<br/>
@result.Substring(0,result.Length - 1)

复制代码

3、基于JQuery的表单异步提交

举个栗子吧:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
$(document).ready(function () {
$("#form1").submit(function (event) {
event.preventDefault();//阻止默认提交事件,改用JS处理提交事件
$.ajax({
type:"Post//表单提交类型
url: "@Url.Content("~/User/Create")",//表单提交的Action方法
data:$("#form1").serialize(), //序列化表单的值为字符串,前提是表单里边的输入标签都要有name属性才可以,序列化后的形式大概是这样的:a=1&b=2&c=3&d=4&e=5
success:function(msg){
$("#result").html(msg);
}
});
return false;
});
});
</script>

复制代码

但是我觉得如果表单提交的数据少的话,可以用这种,如果多的话,就没有必要了,用MVC自带的更好

如何提高Ajax性能

1、适当使用缓存机制

2、使用CDN内容分发来访问Jquery脚本:

​ (1)自己公司架设CDN服务器

​ (2)使用第三方公司的,比如微软,谷歌等公司的CDN,但有时候不太靠谱

3、JS/CSS文件的打包合并(Bundling)及压缩(Minification)

将多个JS或CSS文件打包合并成一个文件,并在网站发布之后进行压缩,从而减少HTTP请求次数,提高网络加载速度和页面解析速度。压缩功能实现了对javascript脚本和CSS进行压缩的功能,它能够去除脚本或样式中不必要的空白和注释,同时能够优化脚本变量名的长度

例如在BundleConfig.cs里面配置捆绑js和css文件:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Web;
using System.Web.Optimization;

namespace MvcExample
{
public class BundleConfig
{
// For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
}
}
}

复制代码

记得在Global.asax中注册一下:

1
BundleConfig.RegisterBundles(BundleTable.Bundles);

页面引用时可以这样引用:

复制代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</head>
<body>
@RenderBody()
</body>
</html>

复制代码

启用JS/CSS文件压缩合并:

  • Web.config中配置
1
<compilation debug="false" targetFramework="4.0" />
  • 在BundleConfig.cs或Global.asax中添加以下代码即可:
1
BundleTable.EnableOptimizations = true;

4、最好将js脚本文件放在view页面下面一点

关于ASP.NET MVC和Ajax的故事,暂且讲到这里吧!