【原文地址】Writing A Page To A String
【原文发表日期】 May 29, 2009
ASP.NET页面通常是将它们内容直接输出到一个请求响应流(response stream)中。这对比较大型的页面来说应该是一个巨大的效率优化,因为这样做就不需要为页面显示而建立很大的缓冲区或者分配很大的字符串。而分配大型字符串的操作经常会在“大型对象堆栈”(Large Object Heap)上获取所需的内存,而这也意味着这些内存块不会被很快地资源回收。
然而,很多情况下你可能确实需要将一个页面的内容输出到一个字符串里以便进行一些后处理工作。关于这点,我N久之前也曾经写过一篇blog介绍了一个方法:就是使用response filter。
不过,最近我学到了Page类中的一个我从没有注意到过的方法,这个方法提供了以上问题的一个更轻量级的解决方案。
我所说的就是CreateHtmlTextWriter这个方法,它是一个保护(protected)成员函数的,而且也是一个虚(virtual)函数的。
以下是一个页面code-behind的代码示例,其中利用了这个函数来对页面的输出内容进行过滤,经此处理后的内容才最终显示在浏览器中。
public partial class FilterDemo : System.Web.UI.Page
{
HtmlTextWriter _oldWriter = null;
StringWriter _stringWriter = new StringWriter();
protected override HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
{
_oldWriter = base.CreateHtmlTextWriter(tw);
return base.CreateHtmlTextWriter(_stringWriter);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
string html = _stringWriter.ToString();
html = html.Replace("REPLACE ME!", "IT WAS REPLACED!");
_oldWriter.Write(html);
}
}
在CreateHtmlTextWriter方法中,我们首先是调用基类的该函数来创建一个原来的HtmlTextWriter,然后将它暂时存放在一个成员变量中。
然后我们还是调用基类的函数来创建一个新的HtmlTextWriter,不过这个对象实例会使用我们自己的StringWrtier作为底层的TextWriter。被传入到Render函数中的HtmlTextWriter就是这个新创建的实例。(在Render函数中)我们首先对这个新的HtmlTextWriter实例调用基类的方法,然后将底层StringWriter的输出内容取出,这样就可以对该部分内容进行所需的处理了。我们最后将最终的输出内容写到原先的HtmlTextWriter中去,因为原先的这个HtmlTextWriter是真正负责将结果写到请求响应中去的。
使用这个技巧的时候有很多值得特别注意的地方。首先,如我先前所提到的,对于大型的页面,以上所做的这些事可能会大大地影响你网页的运行效率和可伸缩性。而且,我也没有针对输出缓存、异步页面等等的情况下测试过上面的技巧,所以你很可能会遇到意想不到的实际结果。
注意,如果你是需要从一个页面调用另一个页面,然后在第一个页面中得到后者的输出内容,那么你可以将你自己的TextWriter实例传到Server.Execute函数中并得到结果,所以这种情况下你无需借助上面所介绍的这个技巧。
打印 | 张贴于 2009-07-01 15:54:46 | Tag:暂无标签
留言反馈