[翻译]ASP.NET MVC 3 开发的20个秘诀(二十)[20 Recipes for Programming MVC 3]:缓存结果数据加速页面载入
议题
随着网站的发展,大量用户访问流行内容和动态内容,这两个方面的因素会增加平均的载入时间,给 Web 服务器和数据库服务器造成大量的请求压力。而大量的数据请求就需要强大的数据库处理能力来支撑。改进更加只能的程序,以极少不必要的数据库访问或动态处理请求,可以节省添加更多服务器的费用以及显著提高 Web 应用程序的整体速度。
解决方案
实现 OutputCacheAttribute 类,缓存不经常改变的数据或者相对固定的动作。
讨论
在 MVC3 中实现缓存是非常容易的事情。将下面的属性添加在某个控制器的动作上即可完成:
[OutputCache (Duration= 600 )]
这个语句将自动缓存该视图 600 秒(或 10 分钟)共享给每个访问此页的用户。这就意味着针对代码进行简单的修改当你有 1000 名用户同时访问此页,只需要通过一次数据加载,可节约数以千计的数据库请求以及 IIS 处理负载。
输出缓存的属性看起来非常简单,但是当你打开引擎盖的时候,也可能会发现这辆车的引擎原来如此复杂。当然除非你原本就是名机械师。这个属性提供了很多关于缓存的方式,必须持续缓存时间,甚至还添加了 SQL 依赖,在这个秘诀中我们会深入探讨一番。
按照时间缓存非常简单,你只需要告诉 MVC 视图应该被缓存多少秒即可。至于缓存存储的位置,是客户端浏览器还是服务器或者是它们的组合,这个问题稍微有点复杂。一个好的做法是首先分析被缓存的内容数据,如果是缓存多个用户共享的数据,缓存到服务器上更为合适;然而如果是个人数据,比如个人定制的网页,还是将其缓存在用户的浏览器中更好。虽然缓存可以说是个伟大的发明,但是它也是有局限性的。通常情况下,缓存的最大限制是内存,不是一切都可以缓存在服务器上。
然而,最有趣的方式还是 SQL 依赖。 OutputCache 允许数据一直被缓存,直到它在数据中的内容发生了实际的变化,这是一个非常有用的功能。就拿图书来举例,新书并不是经常增加的,因此可以为图书设置一个缓存时间(例如 24 小时)。但是,如果在缓存过期之前添加了一本新书,又或者是在漫长的一周或几天里根本就没有添加新书?第一种情况,添加一本新书不能及时出现,用户是会不高兴的。而第二种情况,因为没有新书被添加,每天都要发起不必要的服务器请求。使用 SQL 依赖的方式,像我们希望的那样,当图书的表发生变化时缓存能被立即更新。
这是一个非常棒的功能,在其他编程语言中,你需要手动控制缓存,你需要自己手动更新无效缓存。相信我,这很容易就会让你错过一两个应该正常清除的缓存。
在接下来的示例中,将缓存图书列表页面。默认情况下,如果没有设置 VaryByParam 的值, MVC3 将会自动创建一个唯一的缓存对象。这是个相当棒的功能,按二在这本书上面的例子里,搜索关键字也会作为输入参数之一,但是可能输入数以百计不同的关键字组合,所以这个变量不应该被缓存(这就是上面提高的会产生内存警告的问题)。下面修改后启用缓存的 BooksController 控制器:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using MvcApplication4.Utils;
using PagedList;
namespace MvcApplication4.Controllers
{
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
[OutputCache(Duration= 600 , VaryByParam=
" sortOrder;filter;page " )]
public ViewResult Index( string sortOrder,
string filter, string Keyword, int page = 1 )
{
...
return View(books.ToPagedList(currentPage,
maxRecords));
}
...
}
}
这段代码是非常不错的缓存方案,可以立即降低服务器负载。接下来,将这个例子扩展为 SQL 依赖,在开始工作之前必须还要做一些设置工作。首先是修改 Web.config ,在文件中定义一个数据库链接,然后,将缓存部分的 SQL 依赖设置如下:
<? xml version="1.0" ?>
< configuration >
< connectionStrings >
< add name ="ApplicationServices" connectionString =
"data source=.\SQLEXPRESS;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|aspnetdb.mdf;
User Instance=true" providerName ="System.Data.SqlClient"
/>
< add name ="BooksDBContext" connectionString =
"Server=.\SQLEXPRESS;Database=
MvcApplication4.Models.BookDBContext;
Trusted_Connection=true" providerName =
"System.Data.SqlClient" />
</ connectionStrings >
...
< system.web >
< caching >
< sqlCacheDependency enabled ="true" pollTime ="2000" >
< databases >
< add name = "MvcApplication4.Models.BookDBContext"
connectionStringName = "BooksDBContext" />
</ databases >
</ sqlCacheDependency >
</ caching >
...
</ system.web >
...
</ configuration >
在上面的例子中,将 pollTime 设置为 2000 毫秒,也就是说,每 2 秒中,就会查询一次缓存数据库是否被更改,这个变量设置可以根据你的实际需求来修改。
现在,需要修改 Global.asax.cs 文件,必须在 Application_Start 方法中通过 SqlCacheDependencyAdmin 类的 EnableTableForNotifications 方法为每个需要缓存的表添加监听功能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using MvcApplication4.Models;
using System.Data.Entity;
using System.Globalization;
using System.Threading;
using MvcApplication4.Utils;
namespace MvcApplication4
{
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_Start()
{
Database.SetInitializer<BookDBContext>(
new BookInitializer());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
String connectionString =
System.Configuration.ConfigurationManager.ConnectionStrings
[ " BooksDBContext " ].ConnectionString;
System.Web.Caching.SqlCacheDependencyAdmin.
EnableNotifications(connectionString);
System.Web.Caching.SqlCacheDependencyAdmin.
EnableTableForNotifications(connectionString, " books " );
}
...
}
}
在命令行窗口中,执行如下步骤来完成 SQL 通知的功能配置工作:
点击“开始”按钮 -> 选择“运行”
输入“ cmd ”并回车
cd %windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe -S .\SQLEXPRESS -ed -d MvcApplication4.Models.BookDBContext -et -t books -E
务必要你自己的信息,替换命令中的服务器名、数据库名以及表名。此外,如果你的数据库包含用户名和密码,将需要包含额外的输入参数( -U 和 -P )。命令运行后,应该会显示两条成功信息,第一条,说明数据库缓存功能启用;第二条说明指定表缓存成功。
最后,使用 SQL 依赖缓存需要对 BooksController 稍作修改。此外,因为更换应用程序缓存方式,之前设置的缓存持续时间需要修改为 Int32 的最大值。
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using MvcApplication4.Utils;
using PagedList;
namespace MvcApplication4.Controllers
{
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
[OutputCache(Duration=Int32.MaxValue, SqlDependency =
" MvcApplication4.Models.BookDBContext:books " ,
VaryByParam= " sortOrder,filter,page " )]
public ViewResult Index( string sortOrder, string filter,
string Keyword, int page = 1 )
{
...
return View(books.ToPagedList(currentPage,
maxRecords));
}
...
}
}
在以前的 MVC 版本中,是不支持局部缓存的,这就意味着每次都需要将整个动作的结果进行缓存。目前在 MVC3 版本中开始支持局部缓存。实现这个功能,需要创建一个类似于秘诀 1.14 中使用 Ajax 提交表单的自动作。在 BookCommentsController 的这两个活动都至返回分部视图,而都无需缓存父级动作中的缓存内容。这是一个非常棒的改进,可以将你的代码与那些不经常改变的缓存内容进行有效的隔离。
参考
OutputCacheAttribute SqlCacheDependencyAdmin 原书地址 书籍源代码
Asp.net MVC3 CSS 模板
如果你现在正在用asp.net mvc 3 开发web程序,想让自己的页面有比较好的效果但是对CSS不熟悉的话,可以参考以下视频。
很简单的设置可以做出比较不错的效果。
http://www.youtube.com/watch?v=0O0gi2m_p_o&feature=player_embedded
免费模板网址
http://www.freecsstemplates.org/
我做了几个比较简单的例子
示例代码如下:
https://files.cnblogs.com/huyq2002/CSSTemplate.zip
如果要替换模板
1)把下载下来的images拷贝到对应的image目录
2)拷贝style.css里面的代码到程序里面的site.css
3)运行程序,点击刷新按钮(一定要点刷新看新的模板效果)
Asp.net MVC 利用PartialView 构造自定义菜单
在VS2010中利用Asp.net MVC自带的模板生成的菜单是固定的,没办法更改,下面利用PartialView实现简单的一级菜单。
1) 修改_Layout.cshtml,在<nav>部分改成@{ Html.RenderAction("Menu", "Home");}
< div class = "float-right" >
< section id = "login" >
@Html.Partial("_LogOnPartial")
</ section >
< nav >
@{ Html.RenderAction("Menu", "Home");}
</ nav >
</ div >
MVC将会调用HomeController的Menu方法来显示菜单
2)在HomeController里面添加Menu方法,返回PartialView
public PartialViewResult Menu()
{
List<MenuItem> menus = new List<MenuItem>();
menus.Add( new MenuItem{ Text= " Home " , Controller= " Home " , Action= " Index " });
menus.Add( new MenuItem { Text = " Job " , Controller = " Job " , Action = " Index " });
menus.Add( new MenuItem { Text = " About " , Controller = " Home " , Action = " About " });
menus.Add( new MenuItem { Text = " Contact " , Controller = " Home " , Action = " Contact " });
return PartialView( new MenuModel { Menus = menus });
}
3) 定义一个新的PartialView ,名称为Menu.cshtml,基于原来自动生成的代码修改为:
@model MVCDemo.Models.MenuModel
< ul id = "menu" >
@foreach (var item in Model.Menus)
{
< li >@Html.RouteLink(item.Text, new { controller = item.Controller, action = item.Action })</ li >
}
</ ul >
利用PartialView可以实现自定义多级菜单,并且权限控制也很容易。
完整代码如下:
https://files.cnblogs.com/huyq2002/MVCDemo.zip
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于ASP.NET MVC 3 开发的20个秘诀(二十):缓存结果数据加速页面载入的详细内容...