HttpHandler - 大型 Xml - 标记已损坏。

3

我有一个 HttpHandler,它返回一个大块(~400k 行)的 XML 数据。由于某些原因,在传输过程中数据被损坏了。以下是一个简单的测试用例:

public class SimpleTestCase : HttpHandlerBase
{
    public override bool IsReusable
    {
        get { return false; }
    }

    protected override void HandleRequest(HttpContext context)
    {
        context.Response.ContentType = "application/xml";

        context.Response.Write("<?xml version=\"1.0\"?>" + Environment.NewLine);

        for(var i = 0; i < 400010; i++)
        {
            context.Response.Write("<amount>5</amount>" + Environment.NewLine);
        }
    }
}

当我查看结果时,我发现大约有400,010个实例中大约有60个这样写:60 of the 400,010
  <amount>5amount>

注意到关闭标签的开头部分(</)缺失了。为什么Response流会被破坏?更重要的是,我该如何防止它发生?
更新:如果有关联的话,使用的是Visual Studio 2013、IIS Express、.NET 4.5。

看起来很神秘,像是框架中的一个 bug。尝试每 X 行(比如 500 或 1000)刷新一次响应... 如果我没记错的话,可以使用 Response.Flush。 - MatthewMartin
@MatthewMartin - 谢谢,但是不行。每200次写入刷新一次,但仍然出现这种奇怪的行为。 - Philip Pittle
检查代码在WebDev/Cassini(Visual Studio开发Web服务器)和IIS中是否执行相同。这听起来像响应正在被分块和缓冲,而且某处存在一次性错误。我想没有任何httpmodules拦截此请求并对其进行处理(如gzip压缩或类似操作)。 - MatthewMartin
1
有趣...我在webdev、vs2010rtm、.net 4.0上重现了这个bug。我猜测TextWriter或者它依赖的某个类在处理大型流时存在问题。我查看了参考源代码——它在Write()方法中幕后进行了很多算术运算。 - MatthewMartin
如果您使用StringBuilder将整个字符串一次性发送到响应中,您将获得相同的结果(我已经检查过了)。此外,如果您删除.NewLines,也会出现相同的情况。 - MatthewMartin
显示剩余3条评论
1个回答

2
我已经复制了你的代码,它似乎运行正常。你所看到的问题似乎与浏览器有关。使用你的代码,在 Fiddler、Firefox 和 Chrome 中,我得到了完整的响应,但是 Internet Explorer 在 Normal 模式下和 Source 视图中都不能正确显示响应。然而,如果你在 Internet Explorer 的网络检查工具中查看,你会发现整个响应都已经被接收了。
通过将xml内容封装在一个根标签中,使其成为一个有效的xml文档,Internet Explorer 现在可以正确地显示结果。
public class SimpleTestCase : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "application/xml";

        context.Response.Write("<?xml version=\"1.0\"?>" + Environment.NewLine);

        context.Response.Write("<root>");
        for (var i = 0; i < 400010; i++)
        {
            context.Response.Write("<amount>5</amount>" + Environment.NewLine);
        }
        context.Response.Write("</root>");

        context.Response.Flush();
        context.Response.End();
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

确认了,这似乎是浏览器问题。我可以在 Fiddler 上看到正确的数据传输。奇怪的是浏览器没有正确显示数据。 - Philip Pittle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接