HttpResponse的Filter屬性允許開發人員定義一個派生於Stream的類型,修改Http Entity Body。比如原來的Web應用程序並沒有添加兼容性標記,許多頁面也並沒有使用Master,各處修改增加了許多工作量。編寫一個HttpModule,在Init函數中訂閱HttpApplication的ReleaseRequestState事件。
1 // <summary> 2 /// 初始化 3 /// </summary> 4 /// <param name=”context”>上下文</param> 5 public void Init(HttpApplication context) 6 { 7 context.ReleaseRequestState += new EventHandler(OnReleaseRequestState); 8 }
新建一個派生於Stream的類型HeadRequestFilter,並在ReleaseRequestState事件觸發后為HttpResponse的Filter屬性賦值:
1 /// <summary> 2 /// 釋放請求狀態 3 /// </summary> 4 /// <param name=”sender”>發送方</param> 5 /// <param name=”e”>事件參數</param> 6 private void OnReleaseRequestState(Object sender, EventArgs e) 7 { 8 HttpResponse response = HttpContext.Current.Response; 9 10 response.Filter = new HeadRequestFilter(response.Filter); 11 }
由於我們只需要為head標簽內添加meta標簽,所以HttpResponse原來的HttpResponseStreamFilterSink依然可以被使用。需要修改的是Stream定義的Write和Flush函數。在執行Flush函數前需要通過StringBuilder保存舊有輸出的HTML:
m_buffer.Append(HttpContext.Current.Response.ContentEncoding.GetString(buffer, offset, count));
在調用Flush函數內部插入meta標簽,最后調用HttpResponse輸出修改后的Http Entity Body。下面是一個實現插入meta標簽的HeadResponseFilter示例:
1 public sealed class HeadResponseFilter : Stream 2 { 3 private const String TAG_HEAD_BEGIN = “<head”; 4 private const String TAG_HEAD_END = “</head>”; 5 6 private StringBuilder m_buffer; 7 private Stream m_stream; 8 9 /// <summary> 10 /// 構造函數 11 /// </summary> 12 /// <param name=”stream”>流</param> 13 public HeadResponseFilter(Stream stream) 14 { 15 m_stream = stream; 16 m_buffer = new StringBuilder(); 17 } 18 19 /// <summary> 20 /// 請求 21 /// </summary> 22 public HttpRequest Request 23 { 24 get 25 { 26 return HttpContext.Current.Request; 27 } 28 } 29 30 /// <summary> 31 /// 響應 32 /// </summary> 33 public HttpResponse Response 34 { 35 get 36 { 37 return HttpContext.Current.Response; 38 } 39 } 40 41 /// <summary> 42 /// 可讀 43 /// </summary> 44 public override Boolean CanRead 45 { 46 get { return true; } 47 } 48 49 /// <summary> 50 /// 可查詢 51 /// </summary> 52 public override Boolean CanSeek 53 { 54 get { return true; } 55 } 56 57 /// <summary> 58 /// 可寫 59 /// </summary> 60 public override Boolean CanWrite 61 { 62 get { return true; } 63 } 64 65 /// <summary> 66 /// 長度 67 /// </summary> 68 public override Int64 Length 69 { 70 get { return 0; } 71 } 72 73 /// <summary> 74 /// 位置 75 /// </summary> 76 public override Int64 Position { get; set; } 77 78 /// <summary> 79 /// 刷新 80 /// </summary> 81 public override void Flush() 82 { 83 String rawHtml = m_buffer.ToString(); 84 Int32 headIndex = rawHtml.IndexOf(TAG_HEAD_BEGIN, StringComparison.CurrentCultureIgnoreCase); 85 Int32 headIndex2 = rawHtml.IndexOf(TAG_HEAD_END, StringComparison.CurrentCultureIgnoreCase); 86 87 if ((headIndex > 0) && (headIndex2 > 0) && (headIndex < headIndex2)) 88 { 89 String rawHead = rawHtml.Substring(headIndex, headIndex2 – headIndex + TAG_HEAD_END.Length); 90 XElement headElement = XElement.Parse(rawHead); 91 IEnumerable<XElement> metaElement = headElement.Descendants(“meta”).Where(p => p.Attribute(“http-equiv”) != null); 92 93 if (metaElement.Count() == 0) 94 headElement.Add(new XElement(“meta”, new XAttribute(“http-equiv”, “x-ua-compatible”), new XAttribute(“content”, “IE=7″))); 95 96 rawHtml = String.Concat(rawHtml.Substring(0, headIndex), headElement.ToString(), rawHtml.Substring(headIndex + rawHead.Length)); 97 } 98 99 this.Response.Write(rawHtml); 100 this.Response.Flush(); 101 } 102 103 /// <summary> 104 /// 讀取 105 /// </summary> 106 /// <param name=”buffer”>緩沖區</param> 107 /// <param name=”offset”>偏移量</param> 108 /// <param name=”count”>數量</param> 109 /// <returns>讀取數量</returns> 110 public override Int32 Read(Byte[] buffer, Int32 offset, Int32 count) 111 { 112 return m_stream.Read(buffer, offset, count); 113 } 114 115 /// <summary> 116 /// 查找 117 /// </summary> 118 /// <param name=”offset”>偏移量</param> 119 /// <param name=”origin”>參考點</param> 120 /// <returns>位置</returns> 121 public override Int64 Seek(Int64 offset, SeekOrigin origin) 122 { 123 return m_stream.Seek(offset, origin); 124 } 125 126 /// <summary> 127 /// 設置長度 128 /// </summary> 129 /// <param name=”value”>值</param> 130 public override void SetLength(Int64 value) 131 { 132 m_stream.SetLength(value); 133 } 134 135 /// <summary> 136 /// 寫入 137 /// </summary> 138 /// <param name=”buffer”>緩沖區</param> 139 /// <param name=”offset”>偏移量</param> 140 /// <param name=”count”>數量</param> 141 public override void Write(Byte[] buffer, Int32 offset, Int32 count) 142 { 143 m_buffer.Append(HttpContext.Current.Response.ContentEncoding.GetString(buffer, offset, count)); 144 } 145 }