zoukankan      html  css  js  c++  java
  • 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);
            }
    复制代码

    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);
            }
    复制代码

    注意事项

      对于经常需要编辑的内容的查询页面,如商品列表如使用动态处理静态化页面,则应在编辑商品信息后,删除服务器指定目录下的静态页面,以便于页面更新。

      当然我们也可以在上面的过滤器中的 OnActionExecuting 方法在判断文件是否存在时,先判断本次请求是否是编辑操作,如果是则删除相应的静态文件重新生成即可。

  • 相关阅读:
    关于read函数的一些分析
    条件变量
    epoll的边缘触发与水平触发
    内核态的接收缓冲区和发送缓冲区
    SourceTreet提交时显示remote: Incorrect username or password ( access token )(4种解决办法)
    前端技术汇总+Vue最新快速上手
    MyBatisPlus性能分析插件,条件构造器,代码自动生成器详解
    博客园怎样在Markdown编辑模式下调整图片大小(已解决)
    MyBatisPlus分页查询,删除操作
    idea括号选中时出现一条下滑线(突出显示)打开或关闭方法
  • 原文地址:https://www.cnblogs.com/yy1234/p/10209593.html
Copyright © 2011-2022 走看看