ASP.NET Response.Filter

时间:2013-02-17 19:59:21

标签: asp.net filter response.filter

我需要创建过滤器,将HTML中的标记<h2>替换为<h3>

我的过滤器

public class TagsFilter:Stream
{
    HttpContext qwe;

    public TagsFilter(HttpContext myContext)
    {
        qwe = myContext;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        string html = System.Text.Encoding.UTF8.GetString(buffer);
        html = html.Replace("<h2>", "<h3>");
        qwe.Response.Write(html.ToCharArray(), 0, html.ToCharArray().Length);
    }

我的模块

public class TagsChanger : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.Response.Filter = new TagsFilter(context.Context);
    }

我收到错误System.Web.HttpException:在这种情况下,答案不可用。

3 个答案:

答案 0 :(得分:6)

请看Rick Strahl关于"Capturing and Transforming ASP.NET Output with Response.Filter"的帖子。

  

Response.Filter内容已分块。因此,实现Response.Filter实际上只需要实现自定义流并处理Write()方法以捕获响应输出。乍一看,这看起来很简单 - 你在Write中捕获输出,转换它并在一次传递中写出转换后的内容。这确实适用于少量内容。但是你看,问题是输出是用小缓冲区块(它看起来略低于16k)而不是只有一个Write()语句写入流中,这对于ASP.NET将数据流回到IIS采用较小的块来最小化路由中的内存使用情况。

     

不幸的是,这也使得实现任何过滤例程变得更加困难,因为您无法直接访问所有有问题的响应内容,特别是如果这些过滤例程要求您查看ENTIRE响应以进行转换或者按照我会议中的绅士要求的解决方案所需的时间捕获输出。

     

因此,为了解决这个问题,需要一种稍微不同的方法,它基本上捕获传递到缓存流中的所有Write()缓冲区,然后只有在流完成并准备刷新时才使流可用。

     

当我考虑实现时,我也开始考虑使用Response.Filter实现时的几个实例。每次我必须创建一个新的Stream子类并创建我的自定义功能,但最后每个实现都做了同样的事情 - 捕获输出并转换它。我认为应该有一种更简单的方法来创建一个可重用的Stream类,它可以处理Response.Filter实现常见的流转换。

Rick Strahl编写了自己的流过滤器实现,允许以正确的方式替换文本。

答案 1 :(得分:2)

我做了一个小例子。我认为您必须访问原始流,而不是访问httpContext。

public class ReplacementStream : Stream
{
    private Stream stream;
    private StreamWriter streamWriter;

    public ReplacementStream(Stream stm)
    {
        stream = stm;
        streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
        string html = System.Text.Encoding.UTF8.GetString(buffer);
        html = html.Replace("<h2>", "<h3>");
        streamWriter.Write(html.ToCharArray(), 0, html.ToCharArray().Length);
        streamWriter.Flush();
    }

    // all other necessary overrides go here ...
}

public class FilterModule : IHttpModule
{
    public String ModuleName
    {
        // Verweis auf Name in Web.config bei Modul-Registrierung
        get { return "FilterModule"; }
    }
    void context_BeginRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;
        context.Response.Filter = new ReplacementStream(context.Response.Filter);
    }
    public void Init(HttpApplication context)
    {
       context.BeginRequest += new EventHandler(context_BeginRequest);
    }
}

在SO this post找到解决方案。为我工作。

答案 2 :(得分:2)

问题是你在Init事件中应用过滤器,每个应用程序实例只发生一次(它基本上接近App_Start)。

您需要做的是从Init事件中挂接BeginRequest事件,然后在BeginRequest上应用过滤器。

public void Init(HttpApplication application)
{
    application.BeginRequest += BeginRequest;
}

private void BeginRequest(object sender, EventArgs e)
{
    var app = (HttpApplication)sender;
    var context = app.Context;
    context.Response.Filter = new TagsFilter(context);
}