ASP.NET MVC3 小技巧:局部视图和缓存
在上一篇文章中,我创建了一个Blog项目,今天我打算继续折腾一下这个项目。
如果你还不了解ASP.NET MVC3的布局,你可以先看看这篇文章,应该会对你有所帮助的。
主要讲一下自己对ASP.NET MVC3中的局部视图以及缓存的认识,不多说先上几幅图吧。
第一幅图是博客首页分页栏的截图,第二幅图就是博客的Sidebar了。我分别用 ASP.NET MVC3 提供的两种局部视图实现。 有人可能会问,为什么要用两种不同的方法,你这不是装13吗? 。。。。我想我只能“呵呵”以对了,使用什么方法当然是根据需求而选的。
第三幅图是完成后的页面结构
先说分页栏吧
要做成上面的导航栏,我们需要哪些数据呢? 1. 当前页码 2. 每页显示多少文章 3. 数据库里有多少文章
OK,既然只要需要这些,那我们就在HomeController的IndexAction里通过ViewBag提供给他吧。
public class HomeController : Controller { BlogDB db = new BlogDB(); // GET: /Home/page/5 public ActionResult Index(int page = 1) { int countPerPage=10; var posts = db.Posts.Include("Category") .Include("Tags").Include("Comments") .OrderByDescending(p=>p.CreateTime) .Skip((page - 1) * countPerPage) .Take(10); ViewBag.CurrentPage = page; ViewBag.CountPerPage = countPerPage; ViewBag.PostsCount = posts.Count(); return View(posts); } }
数据有了,就让我们开始创建局部视图吧。
打开右击View文件夹中的Share文件夹,选择添加视图。我这里将他命名为_Pagination,注意
小技巧 : 在 ASP.NET MVC3 中,如果一个视图以"_"开头命名的话,外部是不能单独访问他的,他只能作为局部视图嵌套在其他视图中。
打开刚刚创建好的视图,添加如下代码
@{ int pageCount = ViewBag.PostsCount / ViewBag.CountPerPage + 1; int currentPage = ViewBag.CurrentPage; } <div class="pagination"> <span class="first_page"><a href="/">First</a></span> @for (var i = 1; i <= pageCount; i++) { if (i == currentPage) { <span class="page_num current_page"> <a href="/page/@i">@i</a> </span> } else { <span class="page_num "> <a href="/page/@i">@i</a> </span> } } @if (currentPage == pageCount) { <span class="next_page"><a href="/page/@pageCount">Next</a></span> } else { <span class="next_page"><a href="/page/@(currentPage+1)">Next</a></span> } </div>
我们在Home Index View中调用这个局部视图
@model IEnumerable<Blog.Models.Post> @{ ViewBag.Title = "NinoFocus | Notepad"; } <div id="main"> @Html.Partial("_PostList", Model) <!-- 看这里,看这里,我们通过下面的语句调用他 --> @Html.Partial("_Pagination") </div> <!--#END main-->
恩,好了,分页栏就算完成了。
接下来Sidebar
Sidebar 和 分页栏 不同,因为分页栏只在首页显示,所有首页可以提供数据给他。而Sidebar确实无论哪个页面都要显示的,所以他必须要自己给自己提供数据。
好,看到这里可能有人会想,那还不和上面的一样吗?我在页面上写一些服务器端的代码,提供数据会死啊?
就像这样
<li> <h4 class="h4"> <span>一些酷酷的 <strong>网站</strong></span></h4> <ul> @foreach (var link in new Blog.Models.BlogDB().FriendLinks) { <li> <a href="@link.URL" title="@link.Name"> <strong>@link.Name</strong> </a> - @link.Description </li> } </ul> </li>
会死吗?当然不会啦,这也是一种解决方法啊(虽然我不推荐在)。但是,我想想又觉得不妥啊,Sidebar的数据更新频率很低的啊,这样每次刷新页面或者浏览其他页面都要重新请求数据库,这是不是不妥啊?
为了让他变得妥妥的,同时也充分的压榨一下ASP.NET MVC的特性。我还是决定使用ChildAction了。
添加一个ChildActionController,主要负责一些局部视图的工作(其实就是提供数据用的)。下面我以Sidebar中的友情链接为例,说一下Action的代码。
[ChildActionOnly] [OutputCache(Duration = 3600)] public PartialViewResult SidebarFriendLinks() { var links = db.FriendLinks; return PartialView(links); }
[ChildActionOnly] 属性说明这个Action只能内部调用,不能被外部单独访问。
[OutputCache] 启用缓存,Duration字段是缓存时间,以秒为单位,这里我设为1小时。
为了您的健康Action的返回值类型还是用 PartialViewResult 不要用平时常用的 ActionResult ,不然会死很多脑细胞的,我昨晚就被这个搞死。 ASP.NET MVC 遵循DRY(Don't repeat yourself)原则,如果你没有为ActionResult的View指定模板页的话,他会自动的给你加上默认的模板页。默认的模板页可以在_ViewStart.cshtml文件中指出
@{ Layout = "~/Views/Shared/_Layout.cshtml"; }
如果你看了我上面推荐的关于ASP.NET MVC3布局的文章,你会知道这是好东西的。
让我们模拟一下页面的调用,我们在使用了模板页的页面中调用SidebarFriendlinks,然后SidebarFriendLinks有调用了模板,然后模板页调用了SidebarFriendLinks,然后。。。。然后你就悲剧了啊。
如果您一定要使用ActionResult作为返回值的话,那就给局部页面加上下面的语句吧
@{ Layout = null; }
所以为了健康,还是使用PartialViewResult吧。
恩,就此打住,让我们继续吧。右击SidebarFriendLinks选择添加视图。
让我们打开SidebarFriendLinks.cshtml文件,修改一下@model 后的语句,然后添加页面代码
@model IEnumerable<Blog.Models.FriendLink> <li> <h4 class="h4"> <span>一些酷酷的 <strong>网站</strong></span></h4> <ul> @foreach (var link in Model) { <li> <a href="@link.URL" title="@link.Name"> <strong>@link.Name</strong> </a> - @link.Description </li> } </ul> </li>
然后在_Sidebar.cshtml中调用他
<div class="sidebar"> <ul> @Html.Action("SidebarTags","ChildAction") @Html.Action("SidebarArchive","ChildAction") @Html.Action("SidebarFriendLinks","ChildAction") </ul> </div> <div class="clear"> </div> <!-- END sidebar -->
这样写的 sidebar 以后我是不是就可以通过配置文件来控制里面的内容了呢,嘎嘎噶!!!
最后奉上_Layout.cshtml的代码,只求大家对这个博客的页面结构有个更加清晰的了解
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="Content/Site.css" rel="stylesheet" type="text/css" /> </head> <body class="homepage"> <div id="container"> @Html.Partial("_Header") @Html.Partial("_Navigation") <div id="body"> <div id="content"> @RenderBody() </div> @Html.Partial("_Sidebar") </div> </div> @Html.Partial("_Footer") <!-- Script --> @RenderSection("footerScript",false) <!-- End Script--> </body> </html>
@RenderBody() 就是其他页面填充内容的地方。
@RenderSection("footerScript",false) 预留的空间,第一个参数表示名称,第二个参数如果是false的话,表示不是每个页面都必须往里面添加内容;如果是true的话,就表示使用了这个模板的页面都必须往里面填写内容。
在页面上,可以这样调用
@section footerScript{ ...javascript here }
看看缓存是否有效
打开SQL Server Profiler来监视一下数据库请求。
1. 未开启缓存时
在没有开启缓存的情况下,我每次刷新博客首页,会有5条(我sidebar里放了3个局部页面)数据库请求
为什么使用EF时同样的SQL语句会被请求两次?求解!!! 我这里暂且算他一次先。
2. 开启缓存时
现在我启用sidebar的缓存,来看看刷新页面的数据库请求次数
请求次数从5次,变成2次了。说明缓存成功开启了。呵呵,有点爽爽的。
于是贪得无厌的我又把首页也加了缓存
// // GET: /Home/page/5 [OutputCache(Duration=60*5)] public ActionResult Index(int page = 1)
现在刷新页面看看
没有数据库连接请求了,啦啦啦啦。
貌似博客园的首页也加了缓存吧,好像一两分钟的样子。
posted on 2011-04-12 14:12 nizhuguo 阅读(7555) 评论(20) 编辑 收藏 举报