C# 我如何实现一个HTTP响应过滤器来一次对整个内容进行操作,而不进行分块
正如在其他几篇文章(参见下面的参考资料)中提到的,我正在尝试创建响应过滤器,以便修改另一个web应用程序生成的内容 我使用基本的字符串转换逻辑,并将其封装到从通用FilterBase派生的过滤器中。但是,逻辑必须对全部内容而不是大块内容进行操作。因此,我需要在写块时缓存它们,并在所有写操作完成时执行过滤器 如下所示,我从MemoryStream创建了一个新的ResponseFilter。写入时,内容被缓存到另一个MemoryStream。在Flush中,MemoryStream中的全部内容将转换为字符串,并启动过滤器逻辑。然后,修改后的内容被写回原始流 但是,在每一个请求上(基本上是在前一个过滤器上实例化一个新过滤器时),前一个过滤器的Flush方法就会被执行。此时,由于_cachedStream为空,应用程序在_outputStream.Write()方法上崩溃 事件的顺序如下:C# 我如何实现一个HTTP响应过滤器来一次对整个内容进行操作,而不进行分块,c#,filter,stream,httpresponse,flush,C#,Filter,Stream,Httpresponse,Flush,正如在其他几篇文章(参见下面的参考资料)中提到的,我正在尝试创建响应过滤器,以便修改另一个web应用程序生成的内容 我使用基本的字符串转换逻辑,并将其封装到从通用FilterBase派生的过滤器中。但是,逻辑必须对全部内容而不是大块内容进行操作。因此,我需要在写块时缓存它们,并在所有写操作完成时执行过滤器 如下所示,我从MemoryStream创建了一个新的ResponseFilter。写入时,内容被缓存到另一个MemoryStream。在Flush中,MemoryStream中的全部内容将转换
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);
参考资料:
- 未显式调用Flush。可能是在代码意识到需要新对象时调用,或者可能是作为终结器的结果调用
我认为在任何增量写入之后都可以调用flush,因此,我不确定调用flush是否足以表示一条完整的消息。感谢Jay关于增量写入调用flush的提示,只有在过滤器关闭且尚未关闭的情况下,我才能通过执行过滤逻辑使过滤器按需工作。这样可以确保在流关闭时过滤器只刷新一次。我用几个简单的字段完成了这项工作,_isclose和_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用于增量写入的优点。这应该是答案-它帮助我使用HtmlAgilityPack实现了一个响应过滤器,用于修改html节点上的属性。非常感谢。我不明白为什么在重写Write方法时总是将0作为偏移量?+1。我对您的
FilterBase
和MapServiceJsonResponseFilter
类很感兴趣。。。