繁体   English   中英

如何在ASP.NET中筛选完整的Response?

[英]How to filter the full Response in ASP.NET?

在我的ASP.NET MVC 5应用程序中,我有一个旧的HTML缩小属性,用于删除使用正则表达式的空格。 它可以工作,除非不是因为标记包含需要保留空白的textareapre ,否则它可以工作。

在花了最后两天阅读关于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM