C # MVC Мгновенный ответ на браузер? - PullRequest
4 голосов
/ 05 ноября 2010

Опять же, задавая вопросы 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.

ОК, так чтоя хотел бы начать возвращать что-то клиенту, как только строка начнет собираться.В Webforms я бы заменил все параметры StringBuilder на HttpResponse и использовал бы HttpResponse.Write () вместо StringBuilder.Append (), аналогично следующему:

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

Тогда как каждый маленький кусочекXML был записан в Reponse, текст будет отправлен клиенту.

Проблема, с которой я столкнулся, заключается в том, что ActionResult должен иметь инструкцию return.Я не знаю, как лечить в подобной ситуации, используя маршрут MVC и ActionResult.Возможно, мне нужно использовать что-то кроме ActionResult?

Спасибо всем!

Ответы [ 5 ]

4 голосов
/ 05 ноября 2010

Вы можете изменить свой метод действия, чтобы он возвращал void, а затем написать непосредственно в ответ.
(Это возможно; я пробовал)

2 голосов
/ 13 июня 2011

Создание большого количества XML с StringBuilder может оказать большое давление на вашу память.Если вы можете написать 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конкретный пример - сокращенная версия некоторого кода, который я использую для записи XML-содержимого документа sitemap.xml.В моем случае документ имеет около 30 000 URL-адресов и имеет размер около 2,5 МБ.

2 голосов
/ 06 ноября 2010

Если это не должно быть результатом действия MVC, и вы не хотите нарушать тестируемость / инкапсуляцию, вы можете сделать это так, как мы всегда это делали, с помощью пользовательского IHttpHandler, который направляется прямоответ.

ОБНОВЛЕНИЕ

Пример может не иметь смысла - у вас есть понятие в вашем вопросе.Единственным поворотом было бы пропустить StringBuilder и использовать XmlTextWriter, установленный для потоковой передачи в Response.OutputStream, чтобы пропустить посредника.

Тем не менее, теперь, когда я читаю то, что вы делаете, я бы лично взял точку зрения "строить в автономном режиме и разумно кэшировать", а не беспокоиться о потоковой передаче.Наверное, легче иметь дело с консервированными, чем живыми.

0 голосов
/ 06 ноября 2010

Вы всегда можете сначала загрузить страницу и показать дружественный контент, а затем использовать AJAX для вызова метода действия, который выполняет грязную работу.

0 голосов
/ 06 ноября 2010
public ActionResult Xml()
{
    string xmlString = "xml goes here...";
    return this.Content(xmlString, "text/xml", Encoding.UTF8);
}

Может потребоваться кэширование ActionResult, если вы не хотите создавать его заново при каждом запросе.Посмотрите на атрибут [OutputCache], вы можете кэшировать его по параметру, в течение заданного промежутка времени и т. Д.

Я не уверен, к чему вы клоните, похоже, что вы хотите сделать что-тоасинхронного http-запроса.Вообще говоря, это не так.Клиент отправляет запрос http, сервер генерирует и отправляет ответ обратно.

...