我一直在研究这个。我发现了几个关于这个主题的资源,它们都倾向于使用相同的方法 - 覆盖 Page.Render,使用 HtmlTextWriter 将输出转换为字符串,然后使用一系列编译的正则表达式来删除额外的空格。这是一个例子。
嗯,我试过了,它的工作原理......但是......
在 Safari 5.0 中,这似乎会导致加载图像时出现各种性能问题并出现“服务器太忙”错误。IE 7、FireFox 3.6 和 Google Chrome 6.0 似乎工作正常,但我没有对服务器进行太多压力测试。有时页面生成的时间似乎有滞后,但是一旦将html发送到浏览器,页面就会快速显示。
无论如何,当您考虑它时,让 .NET 构建所有这些选项卡和换行符只是为了再次使用字符串解析将它们全部删除似乎相当愚蠢 - 删除它们的效率最低的方法。覆盖 HtmlTextWriter 并将其传递到主页请求上的树中会更有意义,以避免将它们放入输出中 - 从逻辑上讲,在这种情况下应该有性能提升而不是命中。
即使我只能使用这种方法删除 50% 的空白,它仍然会为正则表达式留下更少的工作——这意味着它应该比单独使用正则表达式时表现得更好。
我尝试使用控制适配器并覆盖几个成员
- 将对 WriteLine() 的所有调用定向到相应的 Write() 方法
- 将 NewLine 属性设置为空字符串
- 覆盖 OutputTabs() 方法并简单地删除代码
- 覆盖 Indent 属性并返回 0
我还尝试覆盖 RenderChildren、Render、BeginRender 和 EndRender 以传入我的自定义 HtmlTextWriter,但我似乎无法让一个简单的标签控件删除其标签之前的选项卡。我还使用 Reflector 对框架进行了深入研究,但我根本无法弄清楚这些字符是如何生成的——我以为我使用的是“包罗万象”的方法,但显然我遗漏了一些东西。
无论如何,这就是我想出的。此代码未按我希望的方式运行。当然,我也尝试过直接覆盖页面上的各种 Render 方法并传入我的自定义 HtmlTextWriter 的实例,但这也不起作用。
Public Class PageCompressorControlAdapter
Inherits System.Web.UI.Adapters.ControlAdapter
Protected Overrides Sub RenderChildren(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.RenderChildren(New CompressedHtmlTextWriter(writer))
End Sub
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.Render(New CompressedHtmlTextWriter(writer))
End Sub
Protected Overrides Sub BeginRender(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.BeginRender(New CompressedHtmlTextWriter(writer))
End Sub
Protected Overrides Sub EndRender(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.EndRender(New CompressedHtmlTextWriter(writer))
End Sub
End Class
Public Class CompressedHtmlTextWriter
Inherits HtmlTextWriter
Sub New(ByVal writer As HtmlTextWriter)
MyBase.New(writer, "")
Me.InnerWriter = writer.InnerWriter
Me.NewLine = ""
End Sub
Sub New(ByVal writer As System.IO.TextWriter)
MyBase.New(writer, "")
MyBase.InnerWriter = writer
Me.NewLine = ""
End Sub
Protected Overrides Sub OutputTabs()
'Skip over the tabs
End Sub
Public Overrides Property NewLine() As String
Get
Return ""
End Get
Set(ByVal value As String)
MyBase.NewLine = value
End Set
End Property
Public Overrides Sub WriteLine()
End Sub
Public Overrides Sub WriteLine(ByVal value As Boolean)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As Char)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal buffer() As Char)
MyBase.Write(buffer)
End Sub
Public Overrides Sub WriteLine(ByVal buffer() As Char, ByVal index As Integer, ByVal count As Integer)
MyBase.Write(buffer, index, count)
End Sub
Public Overrides Sub WriteLine(ByVal value As Decimal)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As Double)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As Integer)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As Long)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As Object)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As Single)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal s As String)
MyBase.Write(s)
End Sub
Public Overrides Sub WriteLine(ByVal format As String, ByVal arg0 As Object)
MyBase.Write(format, arg0)
End Sub
Public Overrides Sub WriteLine(ByVal format As String, ByVal arg0 As Object, ByVal arg1 As Object)
MyBase.Write(format, arg0, arg1)
End Sub
Public Overrides Sub WriteLine(ByVal format As String, ByVal arg0 As Object, ByVal arg1 As Object, ByVal arg2 As Object)
MyBase.Write(format, arg0, arg1, arg2)
End Sub
Public Overrides Sub WriteLine(ByVal format As String, ByVal ParamArray arg() As Object)
MyBase.Write(format, arg)
End Sub
Public Overrides Sub WriteLine(ByVal value As UInteger)
MyBase.Write(value)
End Sub
Public Overrides Sub WriteLine(ByVal value As ULong)
MyBase.Write(value)
End Sub
End Class
如果您不熟悉控制适配器,只需将下面的 xml 放在 ASP.NET App_Browsers 文件夹中的 .browser 文件中。您可以更改 controlType 以将控制适配器应用于标签或其他东西,以实现较小范围的测试。如果我能做到这一点,如果有必要在我的项目中添加所有控件并不是什么大不了的事。
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.Page"
adapterType="PageCompressorControlAdapter"/>
</controlAdapters>
</browser>
</browsers>
无论如何,您会认为只有一个简单的配置设置,例如 VerboseHtml="false" 或 PreserveHtmlFormatting="false" 或类似的东西。如果您查看 MSN.com 的输出,他们正在使用与此类似的某种压缩……而且它似乎非常高效。