3

我需要创建过滤器,将<h2>HTML 中的标签替换为<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:在这种情况下,答案不可用。

4

3 回答 3

7

查看 Rick Strahl 关于“使用 Response.Filter 捕获和转换 ASP.NET 输出”的帖子。

Response.Filter 内容被分块。因此,要有效地实现 Response.Filter 只需要您实现自定义流并处理 Write() 方法以在写入时捕获响应输出。乍一看,这似乎很简单——您在 Write 中捕获输出,对其进行转换,然后一次性写出转换后的内容。这确实适用于少量内容。但是你看,问题是输出是写在小的缓冲区块中(看起来比 16k 小),而不是一个单一的 Write() 语句到流中,这对于 ASP.NET 将数据流式传输回非常有意义IIS 在较小的块中以最大程度地减少途中的内存使用。

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

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

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

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

于 2013-04-19T15:58:32.987 回答
3

我做了一个小例子。我认为您必须访问原始流,而不是访问 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上的这篇文章中找到了解决方案。为我工作。

于 2013-02-17T21:05:38.197 回答
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);
}
于 2013-07-10T06:36:15.437 回答