Фильтр ответов ASP.NET для переформатирования отображаемого вывода страниц ASPX?

Я создал простой HttpModule и поток ответов для переформатирования отображаемого вывода веб-страниц (см. фрагменты кода ниже).

В HttpModule я установил Response.Filter в свой PageStream:

m_Application.Context.Response.Filter = new PageStream(m_Application.Context);

В PageStream я перезаписываю метод Write, чтобы выполнить переформатирование отображаемого вывода:

public override void Write(byte[] buffer, int offset, int count)
{
    string html = System.Text.Encoding.UTF8.GetString(buffer);
    //Do some string resplace operations here...
    byte[] input = System.Text.Encoding.UTF8.GetBytes(html);
    m_DefaultStream.Write(input, 0, input.Length);
}

И это прекрасно работает при использовании его на простых страницах HTML (.html), но когда я использую этот метод на страницах ASPX (.aspx), метод Write вызывается несколько раз, разбивая переформатирование на разные этапы и потенциально разрушая операции замены строк.

Как мне это решить? Есть ли способ, чтобы страница ASPX НЕ вызывала запись несколько раз, например. изменив размер буфера, или я выбрал неправильный подход, используя этот метод Response.Filter для управления отображаемым выводом?


person PropellerHead    schedule 10.10.2009    source источник


Ответы (4)


Я бы просто буферизовал данные в методе Write и выполнял строковые операции в методе Close, например:

private readonly Stream _forwardStream;
private readonly StringBuilder _sb;

// snip

public override void Write (byte[] buffer, int offset, int count)
{
  string chunk = Encoding.UTF8.GetString (buffer, offset, count);
  _sb.Append (chunk);
}

public override void Close ()
{
  string result = GetManipulatedString ();

  byte[] rawResult = Encoding.UTF8.GetBytes (result);
  _forwardStream.Write (rawResult, 0, rawResult.Length);

  base.Close ();
  _forwardStream.Close ();
}

(Может быть, даже лучше, если вы соберете данные в MemoryStream)

person Gabor Szokoly    schedule 10.10.2009

Руководствуясь статьей, предложенной Дарином Димитровым, я закончил следующей реализацией метода Write, который также отлично работает с ASPX-страницами:

public override void Write(byte[] buffer, int offset, int count)
{
    string strBuffer = System.Text.UTF8Encoding.UTF8.GetString (buffer, offset, count);

    if (!strBuffer.Contains("</html>"))
    {
        m_ResponseHtml.Append(strBuffer);
    }
    else
    {
        m_ResponseHtml.Append(strBuffer);
        string  html = m_ResponseHtml.ToString ();

        //Do some string operations here...
        byte[] input = System.Text.Encoding.UTF8.GetBytes(html);
        m_DefaultStream.Write(input, 0, input.Length);           
    }
}

Код использует StringBuilder (m_ResponseHtml) для накопления всего HTML-кода, прежде чем выполнять фактическую обработку строки в отображаемом выводе.

person PropellerHead    schedule 10.10.2009

Возможно, вам потребуется проверить тип контента, прежде чем прикреплять фильтр ответа:

var response = m_Application.Context.Response;
if (response.ContentType == "text/html")
{
    response.Filter = new PageStream(m_Application.Context);
}

Также есть хорошая статья, описывающая фильтры ответов в ASP.NET.

person Darin Dimitrov    schedule 10.10.2009
comment
Хотя ваш ответ не имеет никакого смысла по отношению к моему вопросу, я, естественно, проверяю тип контента перед установкой Response.Filter, предоставленная статья мне помогла. Спасибо. - person PropellerHead; 10.10.2009

Ответ PropellerHead зависит от нахождения закрывающего тега html в финальном буфере, но на самом деле у меня конечный буфер был слишком мал, чтобы вместить весь тег.

Более безопасный (и более эффективный) метод состоит в том, чтобы выполнять только добавление в Write, а затем выполнять строковые операции и вывод в Close.

person jprmsn    schedule 12.06.2014