[转载]asp.net mvc3的静态化实现

[转载]asp.net mvc3的静态化实现 - TerryLiang - 博客园.

静态化处理,可以大大提高客户的访问浏览速度,提高用户体验,同时也降低了服务器本身的压力。在asp.net mvc3中,可以相对容易地处理静态化问题,不用过多考虑静态网页的同步,生成等等问题。我提供这个方法很简单,就需要在需要静态化处理的 Controller或Action上加一个Attribute就可以。下面是我写的一个生成静态文件的ActionFilterAttribute。
[csharp]
using System;
2 using System.IO;
3 using System.Text;
4 using System.Web;
5 using System.Web.Mvc;
6 using NLog;
7
8 ///

9 /// 生成静态文件
10 ///

11 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
12 public class GenerateStaticFileAttribute : ActionFilterAttribute
13 {
14 #region 私有属性
15
16 private static readonly Logger logger = LogManager.GetCurrentClassLogger();
17
18 #endregion
19
20 #region 公共属性
21
22 ///

23 /// 过期时间,以小时为单位
24 ///

25 public int Expiration { get; set; }
26
27 ///

28 /// 文件后缀名
29 ///

30 public string Suffix { get; set; }
31
32 ///

33 /// 缓存目录
34 ///

35 public string CacheDirectory { get; set; }
36
37 ///

38 /// 指定生成的文件名
39 ///

40 public string FileName { get; set; }
41
42 #endregion
43
44 #region 构造函数
45
46 ///

47 /// 默认构造函数
48 ///

49 public GenerateStaticFileAttribute()
50 {
51 Expiration = 1;
52 CacheDirectory = AppDomain.CurrentDomain.BaseDirectory;
53 }
54
55 #endregion
56
57 #region 方法
58
59 public override void OnResultExecuted(ResultExecutedContext filterContext)
60 {
61 var fileInfo = GetCacheFileInfo(filterContext);
62
63 if ((fileInfo.Exists && fileInfo.CreationTime.AddHours(Expiration) < DateTime.Now) || !fileInfo.Exists) 64 { 65 var deleted = false; 66 67 try 68 { 69 if (fileInfo.Exists) 70 { 71 fileInfo.Delete(); 72 } 73 74 deleted = true; 75 } 76 catch (Exception ex) 77 { 78 logger.Error("删除文件:{0}发生异常:{1}", fileInfo.FullName, ex.StackTrace); 79 } 80 81 var created = false; 82 83 try 84 { 85 if (!fileInfo.Directory.Exists) 86 { 87 fileInfo.Directory.Create(); 88 } 89 90 created = true; 91 } 92 catch (IOException ex) 93 { 94 logger.Error("创建目录:{0}发生异常:{1}", fileInfo.DirectoryName, ex.StackTrace); 95 } 96 97 if (deleted && created) 98 { 99 FileStream fileStream = null; 100 StreamWriter streamWriter = null; 101 102 try 103 { 104 var viewResult = filterContext.Result as ViewResult; 105 fileStream = new FileStream(fileInfo.FullName, FileMode.CreateNew, FileAccess.Write, FileShare.None); 106 streamWriter = new StreamWriter(fileStream); 107 var viewContext = new ViewContext(filterContext.Controller.ControllerContext, viewResult.View, viewResult.ViewData, viewResult.TempData, streamWriter); 108 viewResult.View.Render(viewContext, streamWriter); 109 } 110 catch (Exception ex) 111 { 112 logger.Error("生成缓存文件:{0}发生异常:{1}", fileInfo.FullName, ex.StackTrace); 113 } 114 finally 115 { 116 if (streamWriter != null) 117 { 118 streamWriter.Close(); 119 } 120 121 if (fileStream != null) 122 { 123 fileStream.Close(); 124 } 125 } 126 } 127 } 128 } 129 130 ///

131 /// 生成文件Key
132 ///

133 /// ControllerContext 134 /// 文件Key
135 protected virtual string GenerateKey(ControllerContext controllerContext)
136 {
137 var url = controllerContext.HttpContext.Request.Url.ToString();
138
139 if (string.IsNullOrWhiteSpace(url))
140 {
141 return null;
142 }
143
144 var th = new TigerHash();
145 var data = th.ComputeHash(Encoding.Unicode.GetBytes(url));
146 var key = Convert.ToBase64String(data, Base64FormattingOptions.None);
147 key = HttpUtility.UrlEncode(key);
148
149 return key;
150 }
151
152 ///

153 /// 获取静态的文件信息
154 ///

155 /// ControllerContext 156 /// 缓存文件信息
157 protected virtual FileInfo GetCacheFileInfo(ControllerContext controllerContext)
158 {
159 var fileName = string.Empty;
160
161 if (string.IsNullOrWhiteSpace(FileName))
162 {
163 var key = GenerateKey(controllerContext);
164
165 if (!string.IsNullOrWhiteSpace(key))
166 {
167 fileName = Path.Combine(CacheDirectory, string.IsNullOrWhiteSpace(Suffix) ? key : string.Format("{0}.{1}", key, Suffix));
168 }
169 }
170 else
171 {
172 fileName = Path.Combine(CacheDirectory, FileName);
173 }
174
175 return new FileInfo(fileName);
176 }
177
178 #endregion
179 }
[/csharp]
如果大家对于生成的文件和目录有特殊的要求,那可以重写GetCacheFileInfo方法,比如按照日期生成目录等等更复杂的目录和文件结构。当然以上代码只是提供了生成静态页的方法,但是访问如何解决呢? 访问静态文件和规则就需要在HttpApplication的Application_BeginRequest实现了。首先可以设置需要静态化访问的路由地址以html结尾。下面的是一个用于首页的静态化访问的实现,很简单,当然你可以实现比较复杂的逻辑,比如根据文件时间来判断是否应该访问静态文件等等。
[csharp]
protected void Application_BeginRequest(object sender, EventArgs e)
2 {
3 StaticContentRewrite();
4 }
5
6 ///

7 /// 处理静态发布内容
8 ///

9 private void StaticContentRewrite()
10 {
11 if (Context.Request.FilePath == "/" || Context.Request.FilePath.StartsWith("/index.html", StringComparison.OrdinalIgnoreCase))
12 {
13 if (File.Exists(Server.MapPath("index.html")))
14 {
15 Context.RewritePath("index.html");
16 }
17 }

18 }
[/csharp]