在asp.net mvc pipline中替换文本的最佳位置

Wil*_*eys 5 c# asp.net asp.net-mvc performance placeholder


版本2

我已经更新了原始代码,考虑到write方法以块的形式从页面流式传输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

  }

} 
Run Code Online (Sandbox Code Playgroud)

和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();

  }

}
Run Code Online (Sandbox Code Playgroud)

以及Web.config中的以下内容

<system.webServer>
  <modules>
    <remove name="CmsFilterHttpModule" />
    <add name="CmsFilterHttpModule" type="{MY_NAMESPACE}.CmsFilterHttpModule" />
  </modules>
</system.webServer>
Run Code Online (Sandbox Code Playgroud)

这确实可行.

我的问题是,在我开始向后工作之前,这是最好的地方.

此方法正在替换已完成输出上的文本.

我正在寻找从管道角度替换此文本的最快方法.

目前忽略了String.Replace/Stringbuilder的速度以及其他各种方法.我看到优化稍微进一步.

我还没有通过整个管道进行调试,但是我猜这个页面必须是从不同的部分构建的,即布局,视图部分等等,也许更快地替换这些部分的文本.

另外还有任何问题

String bufferContent = UTF8Encoding.UTF8.GetString(buffer);
Run Code Online (Sandbox Code Playgroud)

当使用其他语言日语,中文等

我还必须补充说,我正在尝试将此作为一个单独添加的代码,尽可能少地触及用户站点MVC代码.

ren*_*ene 2

要处理完整的响应,而无需处理调用之间的状态来编写实现,不需要重写该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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个幼稚的实现。您可以优化替换代码并写入流,但只有当您的性能测量表明这种和平的代码位于热路径上时,我才会优化它。