В ASP.NET 2.0, как удалить дополнительные вкладки и разрывы строк из вывода обработанной страницы / элемента управления?
Я изучал это некоторое время. Я нашел несколько ресурсов на эту тему, и все они, как правило, используют один и тот же подход - переопределить 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-файл в файл.browser в папке ASP.NET App_Browsers. Вы можете изменить controlType, чтобы применить адаптер управления к метке или что-то еще для меньшего объема теста. Если я смогу заставить это работать, это не так уж сложно добавить сюда все элементы управления в моем проекте, если это будет необходимо.
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.Page"
adapterType="PageCompressorControlAdapter"/>
</controlAdapters>
</browser>
</browsers>
В любом случае, вы могли бы подумать, что будет простой параметр конфигурации, такой как VerboseHtml="false" или PreserveHtmlFormatting="false" или что-то в этом роде. Если вы посмотрите на выходные данные MSN.com, они используют какое-то сжатие, подобное этому... и оно выглядит очень производительным.
1 ответ
Решение включало использование модифицированной версии модуля компрессора, которую я нашел здесь:
http://omari-o.blogspot.com/2009/09/aspnet-white-space-cleaning-with-no.html
В этом решении реализован пользовательский PageParserFilter, который затем настраивается в файле web.config. Прелесть этого решения состоит в том, что оно фильтрует пустое пространство во время компиляции, поэтому во время выполнения не происходит никакого снижения производительности.
А потом, благодаря Аристосу и Диамандиеву, я искал разумный способ добавить сжатие в поток ответов для браузеров, которые его поддерживают. Я нашел другой модуль с открытым исходным кодом, который можно использовать для этого здесь: http://blowery.org/httpcompress/
Прирост производительности был значительным при комбинации двух методов - гораздо больше, чем при использовании одного или другого. Кажется, что браузеры рендерится намного быстрее, когда вкладки удаляются со страницы.
Что касается статического содержимого, я планирую использовать метод, описанный в этой статье, для сжатия этих файлов (за исключением изображений, разумеется, они уже сжаты): http://www.lostechies.com/blogs/dahlbyk/archive/2010/01/08/script-to-enable-http-compression-gzip-deflate-in-iis-6.aspx
Окончательное решение
Я добавил свое окончательное решение к этому Гисту.