如何实现HTTP响应过滤器一次操作整个内容,无需分块

正如其他几篇文章中所述(请参阅下面的参考资料)我试图创建响应过滤器,以便修改由另一个Web应用程序生成的内容。 我将基本的字符串转换逻辑工作并封装到源自公共FilterBase的Filters中。但是,逻辑必须对完整内容进行操作,而不是对内容进行操作。因此,我需要在写入时缓存块,并在完成所有写入时执行过滤器。 如下所示,我创建了一个从MemoryStream派生的新ResponseFilter。在写入时,内容缓存到另一个MemoryStream。在Flush上,现在在MemoryStream中的完整内容将转换为字符串,并且Filter逻辑将启动。然后将修改后的内容写回原始流。 但是,在每个第二个请求(基本上是在前一个请求上实例化新的Filter)时,正在执行前一个过滤器的Flush方法。此时,由于_cachedStream为空,应用程序在_outputStream.Write()方法上崩溃。 活动顺序如下: 第一次请求 调用Write方法 调用Flush方法 调用Close方法 调用Close方法 此时,应用程序返回并显示正确的内容。 第二个请求 调用Flush方法 应用程序在_outputStream.Write上崩溃。 ArgumentOutOfRangeException(offset)。 继续崩溃(在Visual Studio中) 调用Close方法 我有几个问题: 为什么Close叫两次? 为什么在关闭后调用Flush? 对于Jay的观点,可以在完全读取流之前调用Flush,过滤器逻辑应该驻留在哪里?在关闭?在Flush但是“如果关闭”? 对一次处理整个内容的响应过滤器的正确实现是什么? 注意:如果我不重写Close方法,我会遇到完全相同的行为(减去Close事件)。
public class ResponseFilter : MemoryStream
{
    private readonly Stream _outputStream;
    private MemoryStream _cachedStream = new MemoryStream(1024);

    private readonly FilterBase _filter;

    public ResponseFilter (Stream outputStream, FilterBase filter)
    {
        _outputStream = outputStream;
        _filter = filter;
    }

    // Flush is called on the second, fourth, and so on, page request (second request) with empty content.
    public override void Flush()
    {
        Encoding encoding = HttpContext.Current.Response.ContentEncoding;

        string cachedContent = encoding.GetString(_cachedStream.ToArray());

        // Filter the cached content
        cachedContent = _filter.Filter(cachedContent);

        byte[] buffer = encoding.GetBytes(cachedContent);
        _cachedStream = new MemoryStream();
        _cachedStream.Write(buffer, 0, buffer.Length);

        // Write new content to stream
        _outputStream.Write(_cachedStream.ToArray(), 0, (int)_cachedStream.Length);
        _cachedStream.SetLength(0);

        _outputStream.Flush();
    }

    // Write is called on the first, third, and so on, page request.
    public override void Write(byte[] buffer, int offset, int count)
    {
        // Cache the content.
        _cachedStream.Write(buffer, 0, count);
    }

    public override void Close()
    {
        _outputStream.Close();
    }
}

// Example usage in a custom HTTP Module on the BeginRequest event.
FilterBase transformFilter = new MapServiceJsonResponseFilter();
response.Filter = new ResponseFilter(response.Filter, transformFilter);
参考文献: 如何在站点范围内部署托管HTTP模块? 创建多个(15+)HTTP响应过滤器,继承与组合w /注入     
已邀请:
感谢周杰伦关于Flush被称为增量写入的提示,我已经能够通过仅在Filter关闭且尚未关闭的情况下执行过滤逻辑来使过滤器正常工作。这可确保在Stream关闭时,Filter仅刷新一次。我用几个简单的字段_isClosing和_isClosed完成了这个,如下面的最终代码所示。
public class ResponseFilter : MemoryStream
{
    private readonly Stream _outputStream;
    private MemoryStream _cachedStream = new MemoryStream(1024);

    private readonly FilterBase _filter;
    private bool _isClosing;
    private bool _isClosed;

    public ResponseFilter (Stream outputStream, FilterBase filter)
    {
        _outputStream = outputStream;
        _filter = filter;
    }

    public override void Flush()
    {
        if (_isClosing && !_isClosed)
        {
            Encoding encoding = HttpContext.Current.Response.ContentEncoding;

            string cachedContent = encoding.GetString(_cachedStream.ToArray());

            // Filter the cached content
            cachedContent = _filter.Filter(cachedContent);

            byte[] buffer = encoding.GetBytes(cachedContent);
            _cachedStream = new MemoryStream();
            _cachedStream.Write(buffer, 0, buffer.Length);

            // Write new content to stream
            _outputStream.Write(_cachedStream.ToArray(), 0, (int)_cachedStream.Length);
            _cachedStream.SetLength(0);

            _outputStream.Flush();
        }
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        _cachedStream.Write(buffer, 0, count);
    }

    public override void Close()
    {
        _isClosing = true;

        Flush();

        _isClosed = true;
        _isClosing = false;

        _outputStream.Close();
    }
}
我还没有找到上述其他问题的答案,所以我不会在此时将此答案标记为例外。     
Flush没有被明确调用。当代码实现需要新对象时,或者可能是终结器的结果时,可能会调用它。 我认为可以在任何增量写入之后调用flush,所以我不确定对flush的调用是否足以表明完整的消息。     

要回复问题请先登录注册