用Response.Filter生成静态页[要注意并发问题]
using System.IO; namespace URLRewriter { /// <summary> /// 生成htm静态页面 /// </summary> public class ResponseFilter : Stream { private Stream m_sink; private long m_position; private FileStream fs; public ResponseFilter(Stream sink, string filePath) { m_sink = sink; fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write); } // The following members of Stream must be overriden. public override bool CanRead { get { return true; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return false; } } public override long Length { get { return 0; } } public override long Position { get { return m_position; } set { m_position = value; } } public override long Seek(long offset, System.IO.SeekOrigin direction) { return 0; } public override void SetLength(long length) { m_sink.SetLength(length); } public override void Close() { m_sink.Close(); fs.Close(); } public override void Flush() { m_sink.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return m_sink.Read(buffer, offset, count); } // Override the Write method to filter Response to a file. public override void Write(byte[] buffer, int offset, int count) { //Write out the response to the browser. m_sink.Write(buffer, 0, count); //Write out the response to the file. fs.Write(buffer, 0, count); } } }
上边的这个类在生成静态页的时候,如果.net解析代码时,遇到错误,它依然会生成一个静态页面,而且这个静态页面在程序运行结束的时候,还处于打开状态。
显然这是我们不愿意看到的,而且这个类还不支持并发操作,如果和某一页面的关联的静态页失效了,假定这时候有两个用户同时访问这个页面,其中一个用户正在向静态页面写入数据,另外一个用户却需要访问这个已被别人打开的页面,系统同样会出现错误。基于这两个问题,我把这个类修改成下边的样子,就可以解决上述问题了。
using System.IO; using System.Web; namespace URLRewriter { /// <summary> /// 生成htm静态页面 /// </summary> public class ResponseFilter : Stream { private Stream m_sink; private long m_position; private FileStream fs; private string filePath = string.Empty; public ResponseFilter(Stream sink, string filePath) { this.m_sink = sink; this.filePath = filePath; } // The following members of Stream must be overriden. public override bool CanRead { get { return true; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return false; } } public override long Length { get { return 0; } } public override long Position { get { return m_position; } set { m_position = value; } } public override long Seek(long offset, System.IO.SeekOrigin direction) { return 0; } public override void SetLength(long length) { this.m_sink.SetLength(length); } public override void Close() { this.m_sink.Close(); this.fs.Close(); } public override void Flush() { this.m_sink.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return m_sink.Read(buffer, offset, count); } // Override the Write method to filter Response to a file. public override void Write(byte[] buffer, int offset, int count) { //首先判断有没有系统错误 if (HttpContext.Current.Error == null) { try { if (fs == null) this.fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write); //将数据写入静态文件. this.fs.Write(buffer, 0, count); } catch { if (fs != null) { //关闭流 this.fs.Close(); //删除静态页面 if (File.Exists(filePath)) { File.Delete(filePath); return; } } } } //Write out the response to the browser. this.m_sink.Write(buffer, 0, count); } } }
修改的地方是构造函数和这个方法(public override void Write(byte[] buffer, int offset, int count)),调用的方法分为两种,一种是在页面级别的调用,示例如下:
protected override void OnInit(EventArgs e) { if (!this.IsPostBack) { string filePath = this.Server.MapPath(Common.AppName) + "\\index.htm"; Response.Filter = new AspNetFilter(Response.Filter, filePath); } base.OnInit(e); }
重写Page类的OnInit方法