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

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

议题

现在很多网站都与数据库进行交互。如果网站流量很大,使用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 原书地址 书籍源代码

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏