原标題:MVC 頁面靜态化
最近工作需要,實作頁面靜态化,以前在ASP時代,都是FSO自己手動生成的。
新時代,MVC了,當然也要新技術,網上一搜,找到一種解決方案,是基于MVC3的,實作原理是通過mvc提供的過濾器擴充點實作頁面内容的文本儲存。
基本原理為:
1.為需要靜态化的Action上加一個自定義的實作了IResultFilter的Attribute(具體見下文)
2.添加一條路由規則,實作通路靜态頁面,把它放在原有路由的前面
//http://product/123.html
routes.MapRoute(
"HTMLDefault", // Route name
"product/{id}.html", // URL with parameters
new { controller = "Home", action = "ProductDetails", id = 0 } // Parameter defaults
);
(準備應用在項目中做如下規劃:管事員背景修改/删除産品,同時修改/删除其對應頁面,添加無須建立頁面,因為使用者通路時會自動建立)
另外,原文下有同學反應
不會代碼的人
因為每次隻能寫入一定數量的文字,如果過大就會再次寫入,再次寫入的話,樓主寫了下面這判斷:
if (File.Exists(p))
{
File.Delete(p);
}
存在就給删除了,是以隻寫入最後的一些文字
目前網頁沒太大,是以具體情況不清楚,用到再說了哈。
實作效果如下:

但為了達到以上效果,雖然照般教程,但還是無法實作,原因就是我用的VS2012,MVC4,web.config(網站根目錄下)有所改變,經過對比
發現:
隻要在system.webServer結點下添加一條
即可,否則,因為你路由設定了靜态頁面HTML,它會提示你找不到檔案,404錯誤,切記切記。
以下為轉載的文章,友善學習:
public class StaticFileWriteFilterAttribute : FilterAttribute, IResultFilter
{
public void OnResultExecuted(ResultExecutedContext filterContext)
{
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Filter = new StaticFileWriteResponseFilterWrapper(filterContext.HttpContext.Response.Filter, filterContext);
}
class StaticFileWriteResponseFilterWrapper : System.IO.Stream
{
private System.IO.Stream inner;
private ControllerContext context;
public StaticFileWriteResponseFilterWrapper(System.IO.Stream s, ControllerContext context)
{
this.inner = s;
this.context = context;
}
public override bool CanRead
{
get { return inner.CanRead; }
}
public override bool CanSeek
{
get { return inner.CanSeek; }
}
public override bool CanWrite
{
get { return inner.CanWrite; }
}
public override void Flush
{
inner.Flush;
}
public override long Length
{
get { return inner.Length; }
}
public override long Position
{
get
{
return inner.Position;
}
set
{
inner.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return inner.Read(buffer, offset, count);
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
return inner.Seek(offset, origin);
}
public override void SetLength(long value)
{
inner.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
inner.Write(buffer, offset, count);
try
{
string p = context.HttpContext.Server.MapPath(HttpContext.Current.Request.Path);
if (Path.HasExtension(p))
{
string dir = Path.GetDirectoryName(p);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (File.Exists(p))
{
File.Delete(p);
}
File.AppendAllText(p, System.Text.Encoding.UTF8.GetString(buffer));
}
}
catch (Exception ex)
{
}
}
}
}
我們的類StaticFileWriteFilterAttribute實作了IResultFilter,這個接口有兩個方法,OnResultExecuted和OnResultExecuting,其中OnResultExecuting是在controller中的action代碼執行完畢後,但viewresult執行之前(即頁面内容生成之前)執行;OnResultExecuted方法是在viewresult執行之後(即頁面内容生成之後)執行。
我們在頁面生成之前将StaticFileWriteResponseFilterWrapper類注冊給Response對象的Filter屬性,這裡使用包裝類可以在沒有副作用的情況下注入頁面内容靜态化的代碼,對于處理業務邏輯的action是透明的。
使用方式:
全局注冊:GlobalFilters.Filters.Add(new StaticFileWriteFilterAttribute );
單獨controller注冊
public class MyController:Controller
{
[StaticFileWriteFilter]
public ActionResult MyAction
{
}
}
在Global.asax中的RegisterRoutes 添加路由
routes.MapRoute(
"HTMLDefault", // Route name
"Subject/Index/{ArticleId}_{PageIndex}.html", // URL with parameters
new { controller = "Subject", action = "Index", ArticleId = 0, PageIndex=0 } // Parameter defaults
);
例如使用者通路http://localhost:3509/Home/About.html如果不存在此靜态檔案 則通路action,action通路後則自動生成了此html檔案,下次使用者通路這個位址,就是通路靜态檔案了,不會進入action代碼了。