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
{
// ...
}