asp.net mvc 下使用 HttpResponse.Filter

HttpResponse 的 Filter 属性是一个 Stream,通过重写这个流的方法,可以对 response 对象的输出进行修改。自定义 filter 时,如果直接从 Stream 派生新类,则必须要实现 Stream 的全部抽象方法,而实际应用中,只有 Write 方法才是创建过滤器时最关心的。这里的 HttpResponseFilter抽象类可以提供一点方便。

/// <summary>

/// ResponseFilter 提供一个基类,从此类继承可以方便地创建筛选器类。

/// 子类只须实现 Write 方法,而不必费心于 Stream 类其他抽象方法的实现。

///

/// 对子类的说明

/// (1) 子类必须提供一个公有构造函数,并调用此类的构造函数,以初始化基础流。

/// (2) 子类可以从 Sink 属性获取筛选器的基础流

/// (3) 子类必须实现 Write 方法,以实现筛选逻辑。Write 是从 Stream 继承下来的抽象方法。

///

/// PageTitelFilter 类提供了一个示例,演示怎样实现子类

/// </summary>

public abstract class HttpResponseFilter : Stream

{

private Stream _sink;

private long _position;

/// <summary>

/// 实例化此类的新实例。

/// </summary>

/// <param name="sink">基础流</param>

protected HttpResponseFilter(Stream sink)

{

this._sink = sink;

}

/// <summary>

/// 获取此筛选器的基础流

/// </summary>

protected Stream Sink

{

get

{

return _sink;

}

}

public override sealed long Seek(long offset, SeekOrigin origin)

{

return _sink.Seek(offset, origin);

}

public override sealed void SetLength(long value)

{

_sink.SetLength(value);

}

public override sealed void Close()

{

_sink.Close();

}

public override sealed void Flush()

{

_sink.Flush();

}

public override sealed int Read(byte[] buffer, int offset, int count)

{

return _sink.Read(buffer, offset, count);

}

public override sealed bool CanRead

{

get

{

return true;

}

}

public override sealed bool CanSeek

{

get

{

return true;

}

}

public override sealed bool CanWrite

{

get

{

return true;

}

}

public override sealed long Length

{

get

{

return 0;

}

}

public override sealed long Position

{

get

{

return _position;

}

set

{

_position = value;

}

}

}

从这个类继承,可以很容易的写出一个 filter 类,这个 filter 将页面标题替换成指定的值:

[Obsolete("此类仅作为示例")]

/// <summary>

/// 这个类演示如何实现 HttpResponseFilter 类。

/// 如果一个使用此类作为筛选器,则会把页面的标题

/// 设为传递给构造函数的 title 参数

/// </summary>

public class PageTitleFilter : HttpResponseFilter

{

private string _pageTitle;

public PageTitleFilter(Stream sink, string title)

: base(sink)

{

this._pageTitle = title;

}

public override void Write(byte[] buffer, int offset, int count)

{

byte[] data = new byte[count];

Buffer.BlockCopy(buffer, offset, data, 0, count);

string s = System.Text.Encoding.UTF8.GetString(data);

if (string.IsNullOrEmpty(s) == false)

{

string pattern = @"<title>.*</title>";

string replacement = string.Format("<title>{0}</title>", _pageTitle);

s = Regex.Replace(s, pattern, replacement, RegexOptions.IgnoreCase | RegexOptions.Singleline);

byte[] outData = System.Text.Encoding.UTF8.GetBytes(s);

Sink.Write(outData, 0, outData.GetLength(0));

}

else

{

Sink.Write(buffer, offset, count);

}

}

}

在 asp.net mvc 下,可以使用 ActionFilterAttribute 应用 HttpResponseFilter:

public class HttpResponseFilterAttribute : ActionFilterAttribute

{

public override void OnResultExecuting(ResultExecutingContext filterContext)

{

if (System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath != "/")

{

filterContext.HttpContext.Response.Filter = new PageTitleFilter(filterContext.HttpContext.Response.Filter, "demo title" );

}

}

}

将 HttpResponseFilterAttribute 应用到 MyController,MyController 中所有的 Action 输出的页面标题都将被替换为 "demo title"

[HttpResponseFilterAttribute]

public class MyController : Controller

{

// ...

}