zoukankan      html  css  js  c++  java
  • Asp.Net MVC页面静态化功能实现一:利用IHttpModule和ResultFilter

    由于公司现在所采用的是一套CMS内容管理系统的框架,所以最近项目中有一个需求提到要求实现页面静态化的功能。在网上查询了一些资料和文献,最后采用的是小尾鱼的池塘提供的 利用ResultFilter实现asp.net mvc3 页面静态化实现方式,然后结合IHttpModule过滤并判断当前请求。实现代码如下:

    实现思路:当服务器接收到一条Http请求后,会先进入IHttpModule并分析出当前请求的Url对应的静态页面文件路径。如果该文件存在,直接返回静态页面给客户端,终止本次请求。如果静态页面不存在,则通过路由进入对应的Controller和Action,在服务器即将将html代码返回给客户端的时候,捕获html代码,并保存为html文件。

    一、 添加一个自定义一个筛选器

    1、定义一个类WriteHtmlAttributeWrapper,该类继承自Stream。该代码主要是实现了重写Write方法,将Response.Filter中流的数据保存为html文件(Response.Filter包含即将返回给本次请求客户端的html代码)。

    /// <summary>
    /// 重写筛选器,将返回客户端的html代码保存到本地文件
    /// </summary>
    /// <remarks>
    /// 作者: Traicne
    /// 时间: 2015-10-19
    /// </remarks>
    public class WriteHtmlAttributeWrapper : System.IO.Stream
        {
            private System.IO.Stream inner;
            private ControllerContext context;
            public WriteHtmlAttributeWrapper(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);//当前请求不是后台管理;并且返回客户端是html才生成静态页面
                if (!context.HttpContext.Request.FilePath.ToLower().StartsWith("/admin") && context.HttpContext.Response.ContentType.Equals("text/html"))
                {
                    //静态页面保存路径信息
                    string htmlPath = context.HttpContext.Request.HtmlFilePath();
                    string direcHtmlPath = Path.GetDirectoryName(htmlPath);  
                    if (!Directory.Exists(direcHtmlPath))
                    {
                        Directory.CreateDirectory(direcHtmlPath);
                    }
                    //获取返回客户端的html代码,并进行压缩处理
                    string htmlCode = System.Text.Encoding.UTF8.GetString(buffer); 
                    htmlCode = Regex.Replace(htmlCode, "^\s*", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
                    htmlCode = Regex.Replace(htmlCode, "\r\n", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
                    htmlCode = Regex.Replace(htmlCode, "<!--*.*?-->", string.Empty, RegexOptions.Compiled | RegexOptions.Multiline);
                    //保存文件,这里不能用File.WriteAllText
                    File.AppendAllText(htmlPath, htmlCode);
                }
            }
        }
    View Code

    2、添加一个自定义类WriteHtmlAttribute,该类继承自FilterAttribute, IResultFilter。

    /// <summary>
    /// 自定义筛选器
    /// </summary>
    /// <remarks>
    /// 作者: Traicne
    /// 时间: 2015-10-19
    /// </remarks>
    public class WriteHtmlAttribute : FilterAttribute, IResultFilter
    {
        /// <summary>
        /// 在操作结果执行后调用
        /// </summary>
        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            //当View()中存在@Html.Action时,会出现“不允许进行筛选”的错误,这时需要判断当前Filter是否为空
            //当Action中存在重定向RedirectToAction时,会出现“Object Move To Here”的错误信息,这时需要判断当前返回给客户端的状态码
            //if (filterContext.HttpContext.Response.Filter != null)
            if (filterContext.HttpContext.Response.Filter != null && filterContext.HttpContext.Response.StatusCode.Equals(200))
            {
                //重写筛选器对象
                filterContext.HttpContext.Response.Filter = new WriteHtmlAttributeWrapper(filterContext.HttpContext.Response.Filter, filterContext);
            }
        }
    
        /// <summary>
        /// 在操作结果执行之前调用
        /// </summary>
        public void OnResultExecuting(ResultExecutingContext filterContext)
        {
            
        }
    }
    View Code

    该类有两点点需要注意的地方

    第一:需要对filterContext.HttpContext.Response.Filter是否为Null的判断。因为当你的Action返回的视图View()中存在子Action时,OnResultExecuted()会被执行多次(自定义筛选器WriteHtmlAttribute是对于每一个Action都有效)

    第二:需要对返回给客户端的状态码做一个判断,即filterContext.HttpContext.Response.StatusCode.Equals(200)。因为当的Action中存在某个重定向操作RedirectToAction到另外一个Action的时候,会出现重定向到的页面出现“Object Move To Here”这样的内容信息。

    3、添加自定义筛选器

    添加自定义筛选器可以在Global.asax文件的Application_Start方法中添加,也可以在FilterConfig类中的RegisterGlobalFilters方法中添加。二者都是向GlobalFilterCollection中添加一个筛选器,都是一样的效果。

    //FilterConfig类中的RegisterGlobalFilters方法中添加如下代码
    filters.Add(new WriteHtmlAttribute());
    //或者在Global.asax文件Application_Start方法添加这段代码
    GlobalFilters.Filters.Add(new WriteHtmlAttribute());

     

    二、添加一个自定义IHttpModule类

    添加一个类RouterHttpModule,该类继承自 IHttpModule接口。该类主要功能是对Http请求进行过滤(比如过滤掉资源文件或表单请求),然后根据Url分析出静态页面文件地址,并判断静态页面html文件是否存在,如果存在直接返回静态页面给客户端,否则进入应用程序。

    /// <summary>
    /// 自定义IHttpModule,分析当前请求的Url信息
    /// </summary>
    /// <remarks>
    /// 作者: Traicne
    /// 时间: 2015-10-20
    /// </remarks>
    public class RouterHttpModule : IHttpModule
    {
        public void Init(HttpApplication application)
        {
            application.BeginRequest += this.Application_BeginRequest; //注册事件
        }
    
        private void Application_BeginRequest(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            string filePath = context.Request.FilePath;
            string fileExtension = VirtualPathUtility.GetExtension(filePath);
            //如果当前请求的不是资源文件、不是后台管理、请求中没有表单信息、静态页面存在,则返回静态页面
            if (string.IsNullOrEmpty(fileExtension) && !filePath.ToLower().StartsWith("/admin") && context.Request.Form.Count.Equals(0))
            {
                string htmlPath = context.Request.HtmlFilePath();
                if (File.Exists(htmlPath))
                {
                    context.Response.WriteFile(htmlPath);
                    context.Response.End();
                }
            }
        }
    
        public void Dispose() { }
    }
    View Code

    然后需要在配置文件Web.config中添加节点,应用程序才会执行刚刚自定义的IHttpModule对象。IIS6和IIS7添加节点的方式也不同

    <!--IIS6-->
    <system.web>
      <httpModules>
        <add name="RouterHttpModule" type="GTA.CMS.Site.Web.Common.RouterHttpModule,GTA.CMS.Site.Web"/>
      </httpModules>
    </system.web>
    
    <!--IIS7-->
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true">
        <add name="RouterHttpModule" type="GTA.CMS.Site.Web.Common.RouterHttpModule,GTA.CMS.Site.Web"/>
      </modules>
    </system.webServer>
    View Code
     下一篇将会提到后来我在实现过程中将ResultFilter自定义筛选器实现的功能转移到IHttpModule中来实现 Asp.Net MVC页面静态化功能实现一:利用IHttpModule,摒弃ResultFilter
    
    

    最后这里要注意的是:IHttpModule通过Url分析出来的静态页面文件路径和自定义筛选器通过Url分析出来的静态页面文件路径要一致

     

  • 相关阅读:
    实现ls(课上作业)
    20181217 (2)
    20181217 (1)
    ubuntu开启远程ssh登陆本机功能
    解决ubuntu下Could not get lock的问题
    博客园生成目录结构
    np.mean以及np.std用法
    解决 Could not find a version that satisfies the requirement torch==1.4.0
    github下载ocr模型 windows直接解压出问题
    centos7 连接不上网络解决办法
  • 原文地址:https://www.cnblogs.com/tracine0513/p/4933245.html
Copyright © 2011-2022 走看看