4

再次,询问 MVC noob 问题。原谅我缺乏经验。

我有一种情况,我使用 MVC 路由返回一个大的 XML 文件。有时它可能非常大。目前,我正在使用 StringBuilder 构建我想要的 XML 输出,然后像这样返回它:

var sb = new StringBuilder();
XmlObject.WriteXml(sb);
return Content(sb.ToString(), "text/xml", Encoding.UTF8);

我遇到的是(由于各种原因)XML 博客可能需要很长时间才能生成。

在 XmlObject.WriteXml() 方法中调用了大量其他小方法,这些小方法在调用时输出 XML 的点点滴滴,因此我立即开始构建 XML 字符串,只需要一段时间即可完成。这些方法中的每一个都接受一个 StringBuilder 作为参数,因此可以创建一个然后将其传递到各处,在每个小方法中使用 sb.Append() 来构建最终的 XML blob。

好的,所以我想做的是在字符串开始构建后立即开始向客户端返回一些东西。在 Webforms 中,我会用 HttpResponse 替换所有 StringBuilder 参数,并使用 HttpResponse.Write() 而不是 StringBuilder.Append(),其方式类似于:

this.Response.BufferOutput = false;
XmlObject.WriteXml(Response);

然后,随着每一小段 XML 被写入响应,文本将被发送到客户端。

我遇到的问题是 ActionResult 必须有一个 return 语句。我不知道如何使用 MVC 路由和 ActionResult 进行类似的处理。也许我需要使用 ActionResult 以外的东西?

谢谢大家!

4

5 回答 5

4

您可以将您的操作方法更改为 return void,然后直接写入响应。
(这是可能的;我已经尝试过了)

于 2010-11-05T20:53:32.123 回答
2

如果它不需要是 MVC 操作的结果,并且您不想破坏那里的可测试性/封装性,那么您可以按照我们一直这样做的方式进行操作——使用直接流入响应的自定义 IHttpHandler。

更新

示例可能没有意义-您的问题中有这个概念。唯一的转折是跳过 StringBuilder 并使用 XmlTextWriter 设置流式传输到 Response.OutputStream 以跳过中间人。

也就是说,既然我正在阅读您在做什么,我个人会采取“离线构建并合理缓存”的角度,而不是担心流式传输。它可能比处理罐头更容易处理。

于 2010-11-05T22:31:28.280 回答
2

使用 a 构建大量 XMLStringBuilder会给您的记忆带来很大压力。如果您可以按深度优先顺序编写 XML,请使用XmlTextWriter.

下面是一些将可能大量 XML 写入输出流的示例代码:

public ActionResult SiteMap()
{
    Response.ClearContent();
    Response.ContentType = "application/xml";
    Response.ContentEncoding = Encoding.UTF8;

    using (var context = new MyDataContext())
    {
        using (var xml = new XmlTextWriter(Response.Output))
        {
            xml.WriteStartElement("urlset",
                                  "http://www.sitemaps.org/schemas/sitemap/0.9");

            var url = new UrlHelper(Request.RequestContext);

            xml.WriteStartElement("url");
            xml.WriteElementString("loc", /* some URL */);
            xml.WriteEndElement();

            foreach (var blogPost in context.BlogPosts)
            {
                xml.WriteStartElement("url");
                xml.WriteElementString("loc", /* blog post URL */);
                xml.WriteEndElement();
            }

            xml.WriteEndElement();
            xml.Flush();
        }
    }

    return null;
}

This particular example is an abbreviated version of some code I use to write out the XML contents of a sitemap.xml document. In my case the document has about 30,000 URLs and is about 2.5MB in size.

于 2011-06-13T14:45:10.710 回答
0
public ActionResult Xml()
{
    string xmlString = "xml goes here...";
    return this.Content(xmlString, "text/xml", Encoding.UTF8);
}

如果您不想在每个请求上重新生成它,可能需要考虑缓存 ActionResult。查看 [OutputCache] 属性,您可以通过参数将其缓存指定时间等。

我不确定你在做什么,听起来你想做某种异步 http 请求。一般来说,他们不是。客户端发送一个 http 请求,服务器生成并返回一个响应。

于 2010-11-05T21:00:45.340 回答
0

您总是可以先加载页面并显示友好的内容,然后使用 AJAX 调用执行脏工作的操作方法。

于 2010-11-05T21:59:39.903 回答