[转载]asp.net mvc3的静态化实现 – TerryLiang – 博客园.
静态化处理,可以大大提高客户的访问浏览速度,提高用户体验,同时也降低了服务器本身的压力。在ASP.NET mvc3中,可以相对容易地处理静态化问题,不用过多考虑静态网页的同步,生成等等问题。我提供这个方法很简单,就需要在需要静态化处理的 Controller或Action上加一个Attribute就可以。下面是我写的一个生成静态文件的ActionFilterAttribute。
using System; 2 using System.IO; 3 using System.Text; 4 using System.Web; 5 using System.Web.Mvc; 6 using NLog; 7 8 /// <summary> 9 /// 生成静态文件 10 /// </summary> 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 /// <summary> 23 /// 过期时间,以小时为单位 24 /// </summary> 25 public int Expiration { get; set; } 26 27 /// <summary> 28 /// 文件后缀名 29 /// </summary> 30 public string Suffix { get; set; } 31 32 /// <summary> 33 /// 缓存目录 34 /// </summary> 35 public string CacheDirectory { get; set; } 36 37 /// <summary> 38 /// 指定生成的文件名 39 /// </summary> 40 public string FileName { get; set; } 41 42 #endregion 43 44 #region 构造函数 45 46 /// <summary> 47 /// 默认构造函数 48 /// </summary> 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 /// <summary> 131 /// 生成文件Key 132 /// </summary> 133 /// <param name="controllerContext">ControllerContext</param> 134 /// <returns>文件Key</returns> 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 /// <summary> 153 /// 获取静态的文件信息 154 /// </summary> 155 /// <param name="controllerContext">ControllerContext</param> 156 /// <returns>缓存文件信息</returns> 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 }
如果大家对于生成的文件和目录有特殊的要求,那可以重写GetCacheFileInfo方法,比如按照日期生成目录等等更复杂的目录和文件结构。当然以上代码只是提供了生成静态页的方法,但是访问如何解决呢? 访问静态文件和规则就需要在HttpApplication的Application_BeginRequest实现了。首先可以设置需要静态化访问的路由地址以html结尾。下面的是一个用于首页的静态化访问的实现,很简单,当然你可以实现比较复杂的逻辑,比如根据文件时间来判断是否应该访问静态文件等等。
protected void Application_BeginRequest(object sender, EventArgs e) 2 { 3 StaticContentRewrite(); 4 } 5 6 /// <summary> 7 /// 处理静态发布内容 8 /// </summary> 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 }