ASP.NET MVC中,動態處理頁面靜態化


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

  對於需要靜態化的頁面,第一次訪問某個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需要使用靜態化

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

 /// <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);
        }
View Code

 

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);
        }
View Code

 

注意事項

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

  當然我們也可以在上面的過濾器中的 OnActionExecuting 方法在判斷文件是否存在時,先判斷本次請求是否是編輯操作,如果是則刪除相應的靜態文件重新生成即可。

注:有些地方我想得還不夠充分,希望大家多提意見。

                                                              


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM