由于公司现在所采用的是一套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);
}
}
}

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())
{
//重写筛选器对象
filterContext.HttpContext.Response.Filter = new WriteHtmlAttributeWrapper(filterContext.HttpContext.Response.Filter, filterContext);
}
} /// <summary>
/// 在操作结果执行之前调用
/// </summary>
public void OnResultExecuting(ResultExecutingContext filterContext)
{ }
}

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

第一:需要对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())
{
string htmlPath = context.Request.HtmlFilePath();
if (File.Exists(htmlPath))
{
context.Response.WriteFile(htmlPath);
context.Response.End();
}
}
} public void Dispose() { }
}

然后需要在配置文件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>
 下一篇将会提到后来我在实现过程中将ResultFilter自定义筛选器实现的功能转移到IHttpModule中来实现 Asp.Net MVC页面静态化功能实现一:利用IHttpModule,摒弃ResultFilter

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

Asp.Net MVC页面静态化功能实现一:利用IHttpModule和ResultFilter的更多相关文章

  1. Asp.Net MVC页面静态化功能实现二:用递归算法来实现

    上一篇提到采用IHttpModule来实现当用户访问网站的时候,通过重新定义Response.Filter来实现将返回给客户端的html代码保存,以便用户下一次访问是直接访问静态页面. Asp.Net ...

  2. Asp.Net MVC页面静态化功能实现一:利用IHttpModule,摒弃ResultFilter

    上一篇有提到利用IHttpModule和ResultFilter实现页面静态化功能.后来经过一些改动,将ResultFilter中要实现的功能全部转移到IHttpModule中来实现 Asp.Net ...

  3. ASP.NET MVC 页面静态化操作的思路

    本文主要讲述了在asp.net mvc中,页面静态化的几种思路和方法.对于网站来说,生成纯html静态页面除了有利于seo外,还可以减轻网站的负载能力和提高网站性能.在asp.net mvc中,视图的 ...

  4. 利用ResultFilter实现asp.net mvc 页面静态化

    为了提高网站性能.和网站的负载能力,页面静态化是一种有效的方式,这里对于asp.net mvc3 构架下的网站,提供一种个人认为比较好的静态话方式. 实现原理是通过mvc提供的过滤器扩展点实现页面内容 ...

  5. Asp.net Mvc 页面静态化

    http://www.cnblogs.com/gowhy/archive/2013/01/01/2841472.html

  6. Asp.net动态页面静态化之初始NVelocity模板引擎

    Asp.net动态页面静态化之初始NVelocity模板引擎 静态页面是网页的代码都在页面中,不须要运行asp,php,jsp,.net等程序生成client网页代码的网页,静态页面网址中一般不含&q ...

  7. MVC页面静态化

    MVC 页面静态化   最近工作需要,实现页面静态化,以前在ASP时代,都是FSO自己手动生成的. 新时代,MVC了,当然也要新技术,网上一搜,找到一种解决方案,是基于MVC3的,实现原理是通过mvc ...

  8. MVC 页面静态化

    最近工作需要,实现页面静态化,以前在ASP时代,都是FSO自己手动生成的. 新时代,MVC了,当然也要新技术,网上一搜,找到一种解决方案,是基于MVC3的,实现原理是通过mvc提供的过滤器扩展点实现页 ...

  9. 利用ResultFilter实现asp.net mvc3 页面静态化

    为了提高网站性能.和网站的负载能力,页面静态化是一种有效的方式,这里对于asp.net mvc3 构架下的网站,提供一种个人认为比较好的静态话方式. 实现原理是通过mvc提供的过滤器扩展点实现页面内容 ...

随机推荐

  1. 3.Swift翻译教程系列——Swift基础知识

    英语PDF下载链接http://download.csdn.net/detail/tsingheng/7480427 Swift是用来开发iOS和OS X应用的新语言,可是很多地方用起来跟C或者OC是 ...

  2. Boost.Asio c++ 网络编程翻译(26)

    Boost.Asio-其他特性 这章我们讲了解一些Boost.Asio不那么为人所知的特性.标准的stream和streambuf对象有时候会更难用一些,但正如你所见.它们也有它们的益处.最后,你会看 ...

  3. ArcGIS 10 破解安装(win7 64位)

    上一周换了个win7 64位系统,昨天依照各种各样破解方法装ArcGIS10装了一天,装上之后ArcMap能用,可是装的AO sdk不能用,在VS2008里一拖就报错,确实把我给气坏了.今天早上上班, ...

  4. EXCEL Pivot table manipulate

    Add filter For the Demo time,I would like to filter out the products which not in Red and Black colo ...

  5. 第13章 模版方法模式(Template Method)

    原文  第13章 模版方法模式(Template Method) 模板模式 模板模式 举例:模拟下数据库的update方法,先删除在插入. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...

  6. sql server 汉字的长度

    前几天改了人家程序中的一个小bug,就是输入时长度的校验问题.项目是.Net的,数据库是 sql server的.检查了一下,发现以前的人员把长度给控制小了,数据库中允许输入256的长度,而别人在as ...

  7. 【github课程】创建github仓库和库创建一个版本号,并添加到存储库文件的版本号

    首先,需要登录github注册一个帐号:https://github.com/ 注册帐号登录后,.在右上角,"新仓库": 然后会出现例如以下的界面: 仅仅须要输入仓库的名称,描写叙 ...

  8. monkey命令详解

    标准的monkey 命令 adb shell monkey [options] <eventcount> 例如: adb shell monkey -v    产生500次随机事件,作用在 ...

  9. 前端学习笔记(zepto或jquery)——对li标签的相关操作(二)

    对li标签的相关操作——8种方式获取li标签的第一个元素的内容 1.alert($("ul>li").first().html());2.alert($('ul>li' ...

  10. BZOJ 1355 Baltic2009 Radio Transmission KMP算法

    标题效果:给定一个字符串,求最小周期节(不能整除) 示例Hint这是错误的忽略了就好了 环路部分应该是cab 这个称号充分利用KMP在next自然阵列,那是,n-next[n]它表示一个循环节 POJ ...