ASP.NET MVC中,動態處理頁面靜態化 【轉載】

首先解釋一下什麼是動態處理頁面靜態化html

  對於須要靜態化的頁面,第一次訪問某個Action時,會先執行Action,並在頁面渲染後向Response和服務器中網站的目錄下都寫入須要返回的html,而第二次訪問此頁時,在執行Action前,程序會先在指定目錄下尋找是否存在當前請求對應的靜態頁面,若是有,則直接返回靜態頁面,若是沒有,則按第一次訪問此請求進行處理,即執行Action,並向Response和服務器中網站的目錄下都寫入須要返回的html。利用這種方式,能夠在網站在請求的過程當中,會動態的生成靜態頁面,而無需人工干預,方便快捷。服務器

接下來直接上代碼

複製代碼
    /// <summary>
    /// 頁面靜態化過濾器
    /// 思路:在執行Action前,先判斷此Action返回的View()的靜態文件是否存在
    ///       若是存在,則直接返回靜態文件。
    ///       若是不存在,則利用OnResultExecuting,替換Response中的輸出流,讓渲染後的html寫入到
    ///       本過濾器定義的StringBuilder中,而後在OnResultExecuted中(頁面渲染後),從StringBuilder
    ///       中獲取html,並同時寫入到靜態文件和Response的內置輸出流中
    ///       
    /// 注:因爲我沒找到直接從Response中獲取輸出流的html的方法,所以我這裏是替換了Response中的output屬性,
    /// 替換後,渲染後的結果就會輸出到咱們本身寫的StringBuilder中(此時Response中並無html),此時在渲染後,
    /// 再把StringBuilder中的html,分別寫入靜態文件和Response中(tw.write方法),完成這次請求。
    /// </summary>
    public class StaticHtmlFilter : ActionFilterAttribute
    {
        //用於保存渲染後的html文本
        static StringBuilder sb;
        //這幾個Writer照着寫就好了
        static StringWriter sw;
        static HtmlTextWriter hw;
        static TextWriter tw;
        //自定義的靜態頁面的後綴名
        static string ext = ".html";
        //靜態頁面的絕對路徑(包括後綴名)
        string fileName = null;
        ///靜態頁面的絕對路徑(不包括後綴名)
        static string path = null;
        //靜態文件是否存在
        bool FileExists = false;

        /// <summary>
        /// Action執行前,判斷當前頁面是否已經被靜態化(Views路徑下是否存在html文件)
        /// 若是存在靜態文件則直接設置filterContext的result,即返回html做爲結果,而不執行Action中代碼
        /// 若是不存在靜態頁面文件,則不設置filterContext的result,此時將會執行Action中的代碼
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //根據controller和action信息
            string controller = filterContext.RouteData.Values["controller"].ToString();
            string action = filterContext.RouteData.Values["action"].ToString();
            object id=null;
            //路由中是否包含可選參數id,若是有,則在文件名也要體現
            if  (!filterContext.RouteData.Values.TryGetValue("id", out id))
            {
                path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Views", controller, action);
                fileName = string.Format("{0}{1}", path, ext);
            }
            else
            {
                path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Views", controller, action);
                fileName = string.Format("{0}{1}{2}", path, id.ToString(),ext);
            }
            //拼裝後綴名
           
            FileExists = File.Exists(fileName);
            //若是文件存在,直接返回結果
            if (FileExists)
            {
                filterContext.Result = new FileContentResult(File.ReadAllBytes(fileName), "text/html; charset=utf-8");
            }
        }
        /// <summary>
        /// 執行完Action後,但渲染頁面前執行此處
        /// 渲染頁面的意思是將cshtml中的後臺代碼,翻譯爲前臺代碼
        /// 
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
        if (!FileExists) { //保存html sb = new StringBuilder(); //兩個writer sw = new StringWriter(sb); hw = new HtmlTextWriter(sw); //記住Response中本來輸出流,用於返回本次請求的html,與下一句配合使用 //在渲染結束後,向tw內寫入html內容 tw = filterContext.RequestContext.HttpContext.Response.Output; //過濾器本身輸出流,用於獲取渲染後的html內容 filterContext.RequestContext.HttpContext.Response.Output = hw; } } public override void OnResultExecuted(ResultExecutedContext filterContext) { //若是是靜態文件不存在 if (!FileExists) { //獲取渲染後的html文本 string res = sb.ToString(); //將文本寫入到靜態文件中 new Action(() => File.WriteAllText(fileName, res)).BeginInvoke(null, null); //向Response的輸出流中寫入本次請求的html tw.Write(sb.ToString()); } } }
複製代碼

什麼樣的Action適合靜態化?

我認爲有兩種Action須要使用靜態化async

1.登陸頁面等無需向Action中傳入參數而直接返回View的Action須要靜態處理。ide

複製代碼
 /// <summary>
        /// 登陸
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [StaticHtmlFilter]
        public ActionResult Login()
        {

            var model = new LoginDto
            {
                ReturnUrl = Request.QueryString["ReturnUrl"],
                LoginName = "admin",
                Password = "qwaszx"
            };
            if (User.Identity.IsAuthenticated)
            {
                if (model.ReturnUrl.IsNotBlank())
                    return Redirect(model.ReturnUrl);
                return RedirectToAction("Index");
            }
            return View(model);
        }
複製代碼

 

2.經過一個參數進行查詢的Action(注意是查詢,非編輯)網站

複製代碼
        /// <summary>
        /// 編輯
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [StaticHtmlFilter]
        public async Task<ActionResult> Edit(string id)
        {
            var model = await _menuService.Find(id);
            return View(model);
        }
複製代碼

 

注意事項

  對於常常須要編輯的內容的查詢頁面,如商品列表如使用動態處理靜態化頁面,則應在編輯商品信息後,刪除服務器指定目錄下的靜態頁面,以便於頁面更新。ui

  固然咱們也能夠在上面的過濾器中的 OnActionExecuting 方法在判斷文件是否存在時,先判斷本次請求是不是編輯操做,若是是則刪除相應的靜態文件從新生成便可。spa

相關文章
相關標籤/搜索