議題
現在很多網站都與數據庫進行交互。如果網站流量很大,使用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 />”標記。
參考