[英]How to filter the full Response in ASP.NET?
在我的ASP.NET MVC 5应用程序中,我有一个旧的HTML缩小属性,用于删除使用正则表达式的空格。 它可以工作,除非不是因为标记包含需要保留空白的textarea
或pre
,否则它可以工作。
在花了最后两天阅读关于SO的无数问题以及他们关于如何使用任何东西进行缩小的答案之后,我决定使用HtmlAgilityPack。 使用LINQPad,我拼凑了代码,据我目前所知,这些代码完全可以生成我想要的:
var html = GetHtml();
var document = new HtmlAgilityPack.HtmlDocument();
document.LoadHtml(html);
var spans = document.DocumentNode.Descendants().Where(
d =>
d.NodeType == HtmlNodeType.Element
&& d.Name == "span").SelectMany(
d => d.ChildNodes.Where(
cn => cn.NodeType == HtmlNodeType.Text)).ToList();
// Some spans have content that needs to be trimmed.
foreach (var span in spans) {
span.InnerHtml = span.InnerHtml.Trim();
}
var nodes = document.DocumentNode.Descendants().Where(
d =>
(d.NodeType == HtmlNodeType.Text
&& d.InnerText.Trim().Length == 0)
|| (d.NodeType == HtmlNodeType.Comment
&& d.InnerText.Trim() != "<!DOCTYPE html>")).Select(
d => d).ToList();
foreach (var node in nodes) {
node.Remove();
}
using (var stream = new MemoryStream()) {
document.Save(stream);
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream)) {
reader.ReadToEnd().Dump();
}
}
因此,由于这会在LINQPad中产生我想要的结果,因此将其复制到我的属性中,但是很快我就发现它并不是那么容易。 因为Response.Filter
按块写入的,所以如果响应大于单个块,则最终会陷入混乱。
据我了解,我需要捕获过滤器的完整响应,然后使用上面的代码删除空格,然后将其写回到过滤器中。 不幸的是,我对如何处理整个过程有些困惑。 我知道如何从大块中捕获全部流,但是之后我不知道该怎么办。 我要求任何有关如何完成我想完成的事情的帮助。 提前致谢!
这是当前存在的属性和流类。 老实说,我不完全知道某些代码是否必要……就像我之前说的那样,这是遗留代码,并且已经存在至少五年了。
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class MinifyHtmlAttribute :
ActionFilterAttribute {
public override void OnActionExecuted(
ActionExecutedContext filterContext) {
if (filterContext != null
&& !filterContext.IsChildAction) {
filterContext.HttpContext.Response.Filter = new MinifyHtmlStream(filterContext.HttpContext);
}
}
}
internal sealed class MinifyHtmlStream :
MemoryStream {
private readonly HttpContextBase Context;
private readonly Stream Stream;
public MinifyHtmlStream(
HttpContextBase httpContextBase) {
Context = httpContextBase;
Stream = httpContextBase.Response.Filter;
}
public override void Write(
byte[] buffer,
int offset,
int count) {
var source = Encoding.UTF8.GetString(buffer);
if (Context.Response.ContentType == "text/html") {
var document = new HtmlDocument();
document.LoadHtml(source);
var spans = document.DocumentNode.Descendants().Where(
d =>
d.NodeType == HtmlNodeType.Element
&& d.Name == "span").SelectMany(
d => d.ChildNodes.Where(
cn => cn.NodeType == HtmlNodeType.Text)).ToList();
// Some spans have content that needs to be trimmed.
foreach (var span in spans) {
span.InnerHtml = span.InnerHtml.Trim();
}
var nodes = document.DocumentNode.Descendants().Where(
d =>
(d.NodeType == HtmlNodeType.Text
&& d.InnerText.Trim().Length == 0)
|| (d.NodeType == HtmlNodeType.Comment
&& d.InnerText.Trim() != "<!DOCTYPE html>")).Select(
d => d).ToList();
foreach (var node in nodes) {
node.Remove();
}
document.Save(Stream);
}
}
}
我想出了一个令我满意的解决方案。 我添加了一个MemoryStream
来缓冲所有块,然后对其进行缩小,最后将其传递回过滤器。 解析和最小化的性能对我来说很好,但是我的应用程序仅供内部使用,用户数量很少。 这是我想出的最终代码:
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
internal sealed class MinifyHtmlAttribute :
ActionFilterAttribute {
public override void OnActionExecuted(
ActionExecutedContext filterContext) {
if (filterContext == null
|| filterContext.IsChildAction) {
return;
}
filterContext.HttpContext.Response.Filter = new MinifyHtmlStream(filterContext.HttpContext);
}
}
internal sealed class MinifyHtmlStream :
MemoryStream {
private readonly MemoryStream BufferStream;
private readonly HttpContextBase Context;
private readonly Stream FilterStream;
public MinifyHtmlStream(
HttpContextBase httpContextBase) {
BufferStream = new MemoryStream();
Context = httpContextBase;
FilterStream = httpContextBase.Response.Filter;
}
public override void Flush() {
BufferStream.Seek(0, SeekOrigin.Begin);
if (Context.Response.ContentType != "text/html") {
BufferStream.CopyTo(FilterStream);
return;
}
var document = new HtmlDocument();
document.Load(BufferStream);
var spans = document.DocumentNode.Descendants().Where(
d =>
d.NodeType == HtmlNodeType.Element
&& d.Name == "span").SelectMany(
d => d.ChildNodes.Where(
cn => cn.NodeType == HtmlNodeType.Text)).ToList();
// Some spans have content that needs to be trimmed.
foreach (var span in spans) {
span.InnerHtml = span.InnerHtml.Trim();
}
var nodes = document.DocumentNode.Descendants().Where(
d =>
(d.NodeType == HtmlNodeType.Text
&& d.InnerText.Trim().Length == 0)
|| (d.NodeType == HtmlNodeType.Comment
&& d.InnerText.Trim() != "<!DOCTYPE html>")).Select(
d => d).ToList();
foreach (var node in nodes) {
node.Remove();
}
document.Save(FilterStream);
}
public override void Write(
byte[] buffer,
int offset,
int count) {
BufferStream.Write(buffer, offset, count);
}
}
您可以尝试使用TextWriter代替stream。 然后使用replace方法使用string.empty删除空格,然后保存文档。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.