2013-12-24 2 views
5

VERSION 2Лучшее место, чтобы заменить текст в ASP.NET MVC pipline

Я обновил исходный код, принимая во внимание тот факт, что метод записи потокового в HTML на странице в кусках.

Как указано «Поскольку у вас не гарантируется, что« THE_PLACEHOLDER »записывается в непрерывный блок байтов в записи. Вы можете получить «THE_PLACEH» в конце одного вызова для записи и «OLDER» в начале следующего.

Я исправил это, поставив полное содержимое потока в Stringbuilder и выполнив любое обновление, которое требуется для метода Close.

Сделав это, я задаю тот же вопрос снова ниже ....


Я работаю на CMS, которая просто заменяет заполнитель с текстом CMS.

У меня есть следующее, которое работает так, как должно.

Я переопределены в IHttpModule

public class CmsFilterHttpModule : IHttpModule { 

    // In the Init method, register HttpApplication events by adding event handlers. 
    public void Init(HttpApplication httpApplication) { 

    httpApplication.ReleaseRequestState += new EventHandler(this.HttpApplication_OnReleaseRequestState); 

    } 

    /// <summary> 
    /// HttpApplication_OnReleaseRequestState event handler. 
    /// 
    /// Occurs after ASP.NET finishes executing all request event handlers. 
    /// This event causes state modules to save the current state data. 
    /// </summary> 
    private void HttpApplication_OnReleaseRequestState(Object sender, EventArgs e) { 

    HttpResponse httpResponse = HttpContext.Current.Response; 

    if (httpResponse.ContentType == "text/html") { 

     httpResponse.Filter = new CmsFilterStream(httpResponse.Filter); 

    } 

    } 

    public void Dispose() { 

    //Empty 

    } 

} 

и MemoryStream

public class CmsFilterStream : MemoryStream { 

    private Stream  _responseStream; 
    private StringBuilder _responseHtml; 

    public CmsFilterStream(Stream inputStream) { 

    _responseStream = inputStream; 
    _responseHtml = new StringBuilder(); 

    } 

    /// <summary> 
    /// Writes a block of bytes to the current stream using data read from a buffer. 
    /// </summary> 
    /// <param name="buffer">The buffer to write data from.</param> 
    /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param> 
    /// <param name="count">The maximum number of bytes to write.</param> 
    public override void Write(Byte[] buffer, Int32 offset, Int32 count) { 

    if (buffer == null) { throw new ArgumentNullException("buffer", "ArgumentNull_Buffer"); } 
    if (offset < 0) { throw new ArgumentOutOfRangeException("offset", "ArgumentOutOfRange_NeedNonNegNum"); } 
    if (count < 0) { throw new ArgumentOutOfRangeException("count", "ArgumentOutOfRange_NeedNonNegNum"); } 
    if (buffer.Length - offset < count) { throw new ArgumentException("Argument_InvalidOffLen"); } 

    String bufferContent = UTF8Encoding.UTF8.GetString(buffer, offset, count); 

    _responseHtml.Append(bufferContent); 

    } 

    public override void Close() { 

    _responseHtml.Replace("THE_PLACEHOLDER", "SOME_HTML"); 

    _responseStream.Write(UTF8Encoding.UTF8.GetBytes(_responseHtml.ToString()), 0, UTF8Encoding.UTF8.GetByteCount(_responseHtml.ToString())); 

    _responseStream.Dispose(); 

    base.Close(); 

    } 

} 

и следующее в Web.config

<system.webServer> 
    <modules> 
    <remove name="CmsFilterHttpModule" /> 
    <add name="CmsFilterHttpModule" type="{MY_NAMESPACE}.CmsFilterHttpModule" /> 
    </modules> 
</system.webServer> 

Это делает работу, как я требую.

Мой вопрос в самом деле - это лучшее место в трубопроводе, чтобы сделать это, прежде чем я начну работать назад.

Этот метод заменяет текст на завершенном выходе.

Я ищу самый быстрый способ заменить этот текст с точки зрения трубопровода.

На данный момент игнорируется скорость String.Replace/Stringbuilder и различные другие методы. Я вижу, что оптимизация немного дальше.

Я еще не отлаживал весь конвейер, но, хотя я предполагаю, что эта страница должна быть построена из разных частей, т. Е. Макетов, видов частичных и т. Д. И т. Д., Возможно, их быстрее заменить текст в этих частях.

Кроме того, в дополнение будут ли какие-либо проблемы с

String bufferContent = UTF8Encoding.UTF8.GetString(buffer); 

при использовании других языков японский, китайский и т.д.

Я должен также добавить, что я пытаюсь сделать это как отдельный добавлен фрагмент кода, который затрагивает код сайта MVC для пользователей как можно меньше.

+2

Вы изучали фильтр действий «OnActionExecuted»? – xandercoded

+0

Я еще не смотрел в глаза другим. На самом деле это мой вопрос. Другие люди переживают, мнения, разные способы люди подошли к этому и т. Д. –

+0

Также я должен добавить, что я пытаюсь сделать это как отдельный добавленный фрагмент кода, который как можно меньше затрагивает исходный код MVC. Так что это действительно исключает действие фильтра. –

ответ

1

Чтобы обработать полный отклик без путаницы с состоянием между вызовами для написания вашей реализации, не нужно переопределять метод Write, необходим только метод Close, потому что вам сначала нужно захватить ВСЕ байты перед преобразованием ,Это реализация, которая работает:

public class CmsFilterStream : MemoryStream { 

    private Stream  _responseStream; 

    public CmsFilterStream(Stream inputStream) { 
     _responseStream = inputStream; 
    } 

    public override void Close() { 
     var allHtml = UTF8Encoding.UTF8.GetString(this.ToArray()); // get ALL bytes!! 
     allHtml = allHtml.Replace("THE_PLACEHOLDER", "SOME_HTML"); 

     var buf =UTF8Encoding.UTF8.GetBytes(allHtml); 
     _responseStream.Write(buf,0, buf.Length); 

     _responseStream.Flush(); // I assume the caller will close the _responseStream 

     base.Close(); 
    } 
} 

Это наивная реализация. Вы можете оптимизировать код замены и записывать в поток, но я бы только оптимизировал это, если ваши измерения производительности показывают, что этот мир кода находится на горячем пути.

Смежные вопросы