[翻译]ASP.NET MVC 3 开发的20个秘诀(十七)[20 Recipes for Programming MVC 3]:卷帘式分页加载

议题

现在很多网站都与数据库进行交互。如果网站流量很大,使用SQL来检索数据会带来非常大的压力。更重要的是,用户希望在点击链接之后15秒内得到响应的内容,而在页面加载的时,显示之外滚动条下面的内容可能多数内容都是不必要的(滚动条之外没显示的部分)。为了解决这个问题,采取内容“需求点播”方式加载。页面首先会加载足够的内容,当用户在阅读并向下滚动的时候,页面会在不影响用户阅读体验的情况下继续加载更多的内容。

 

解决方案

当用户开始滚动网站内容时,使用JQuery将前期加载的内容具体数值传回异步控制器,然后按需加载相关的内容。

 

讨论

异步控制器可能是MVC程序集中迄今为止被利用最少的或最不为人所知的控制器,当然也有可能是不知道怎么用它。以下内容是摘抄自MSDN网站的介绍信息:

 

在可能出现线程不足的应用程序中,您可以配置通过异步方式处理操作。异步请求与同步请求所需的处理时间相同。例如,如果某个请求生成一个需要两秒钟来完成的网络调用,则该请求无论是同步执行还是异步执行都需要两秒钟。但是,在异步调用的过程中,服务器在等待第一个请求完成的过程中不会阻塞对其他请求的响应。因此,当有许多请求调用长时间运行的操作时,异步请求可以防止出现请求排队的情况。

 

在这个示例中,使用异步请求将是个完美的解决方案,当新用户在发起更为重要的请求时,它将会自动释放IIS资源,因为其中用户的大多数“需求点播”是不太重要的,因为大多数人甚至不会注意到正在加载的额外的内容。

 

在大多数社交网站中,用户的批注信息更多可能包含的是活动信息。在以前的秘诀中,实现了为书记添加评论的功能。在这个例子中,将会修改页面,列出最近的评论。当用户为了查看更多的评论,他们就会开始滚动,一旦用户开始滚动页面,就发起Ajax请求,请求异步控制器获取剩余部分评论。

 

首先,修改Home/Index视图,使其显示最近的评论信息。提供书籍最近的相关评论并显示查看书籍基本资料的相关链接。创建新的控制器用来显示评论,这个视图将会调用render方法来显示剩下的信息。

@model IEnumerable<MvcApplication4.Models.BookComment>
@{
ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit
<a href="http://asp.net/mvc"
title
="ASP.NET MVC Website">
http://asp.net/mvc </a>.
</p>
<script type="text/javascript">
var lastY = 0;
var currentY = 0;
var page = 1;
var maxPages = @ViewBag.maxPages;
$(window).scroll(
function () {
if (page < maxPages) {
currentY
= $(window).scrollTop();
if (currentY - lastY > 200 * (page - 1)) {
lastY
= currentY;
page
++;
$.get(
'CommentFeed/Comments?page=' + page,
function(data) {
$(
'#comments').append(data);
});
}
}
});
</script>
<div id="comments">
<h2>Recent Comments</h2>
@Html.Partial("../CommentFeed/Comments", Model)

</div>

在上面示例代码中,当浏览器窗体滚动,JavaScript代码就开始执行。在这段代码中定义了一些Javascript全局变量,保持追踪当前滚动条“Y”坐标的位置,最后“Y”坐标的位置和当前被检索到的页面位置。当窗口的ScrollTop减去“Y”坐标最后的位置大于某个具体数字,则通过Ajax请求书籍的其他评论信息。为确保新内容能及时被加载,必须要根据自己网站的内容高度,调整到最佳的像素值。

 

接下来,需要修改HomeController添加检索书籍评论列表。为了确保最新的评论首先显示,排序使用创建日期降序的排列方法。为了减轻数据库的负载,每次只加载固定数量的评论而不是全部,但是也要保证,在滚动时显示足够的内容。在下面的示例当中,评论的加载数量将会限制为3条。页面的最大加载次数也被限制为评论总数除以3的结果。设置最大页数,以防止在加载完毕后,产生无效Ajax请求。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Globalization;
using System.Data.Entity;
using MvcApplication4.Models;
namespace MvcApplication4.Controllers
{
public class HomeController : Controller
{
private BookDBContext db = new BookDBContext();
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";

// Get our recent comments
var bookcomments = db.BookComments.Include(
b => b.Book).OrderByDescending(b => b.Created).
Take(3);
var count = db.BookComments.Count();
ViewBag.maxPages = count / 3 + 1;
return View(bookcomments);
}
...
}
}

 

接下来,需要复制一个新的异步控制器。选中Controllers文件夹,右键单击选择“添加”→“控制器”,将新控制器命名为“CommentFeedController”。这个控制器不需要设置基架选项以及其他内容,直接点击“添加”即可。(译者注:然后将新创建的控制器类的父类改为“AsyncController

 

这个控制器与之前的默认控制器看起来会有一些区别。异步控制器,每个视图都会有两个方法。第一个方法是用来实现异步请求(例如,获取评论信息)。第二个方法,是在异步调用时返回或显示接收到的结果。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using System.Data.Entity;

namespace MvcApplication4.Controllers
{
public class CommentFeedController : AsyncController
{
private BookDBContext db = new BookDBContext();
public void CommentsAsync(int page)
{
AsyncManager.OutstandingOperations.Increment();

AsyncManager.Sync(() =>
{
var bookcomments = db.BookComments.Include(
b => b.Book).OrderByDescending(b =>
b.Created).Skip(page * 3).Take(3);
AsyncManager.Parameters["bookcomments"] =
bookcomments;
AsyncManager.OutstandingOperations.Decrement();
});
}

public ActionResult CommentsCompleted(
IEnumerable<BookComment> bookcomments)
{
return PartialView(bookcomments);
}
}
}

第一个方法,“CommentsAsync”,接收从Javascript传回的当前的页码,使用这个值来检索接下来的3条评论。首先是调用OutstandingOperations来通知未完成的请求挂起。然后再将检索评论的代码作为一个方法变量执行第二步操作,最后,再从未完成的计数器中将执行方法减去。在这里最重要的是递增和递减在计数器中的匹配,当递增和递减计数器相同的一段时间后,同步管理器将取消请求,否则,请求永远无法结束。

 

第二个方法,接收书籍的评论信息,并返回一个分部视图结果。这是一个与Home/Index视图相同的分部视图。在这里最后一步就是创建这个分部视图。右键单击“Views”文件夹,选择“添加”→“新建文件夹”,并将文件夹命名为“CommentFeed”,然后右键单击此文件夹,选择“添加”→“视图”,将其命名为“Comments”,然后确保选中创建视图对话框中的“创建分部视图”选项,然后点击“添加”。

 

@model IEnumerable<MvcApplication4.Models.BookComment>
@foreach (var item in Model) {
<h3><a href="@Url.Action("Details", "Books", new {
ID
=item.Book.ID } )">
@Html.DisplayFor(modelItem => item.Book.Title)
</a></h3>
<h4>Comment Posted: @Html.DisplayFor(
modelItem => item.Created)</h4>
<p>@MvcHtmlString.Create(Html.Encode(item.Comment).Replace(
Environment.NewLine, "<br />"))</p>

}

 

如上所示,首先将评论按照创建时间排序循环取出,显示书籍标题以及详情链接,评论的创建日期以及最后的评论文本。因为评论中有可能会包含换行符,将其中换行符替换为“<br />”标记。

 

 

参考

Asynchronous Controllers 原书地址 书籍源代码

posted on 2011-12-26 10:23  O2DS  阅读(3252)  评论(3编辑  收藏  举报

导航