Контроллер MVC, использующий поток ответов

Я использую MVC 3. Я хотел бы динамически создавать CSV-файл для загрузки, но я не уверен в правильности подхода, ориентированного на MVC.

В обычном ASP.net я бы написал что-то вроде:

Response.ClearHeaders();
Response.ContentType = "text/csv";
Response.AddHeader("content-disposition", attachment;filename='Test.csv'");
Response.Write("1,2,3");
Response.End();

Я просмотрел действие ContentResult, но оказалось, что мне нужно будет создать результат в виде строки, т.е.

return Content(myData, "text/csv");

Я мог бы, я полагаю, построить строку, но поскольку эти файлы могут быть длиной в несколько тысяч строк, мне это кажется неэффективным.

Может ли кто-нибудь указать мне в правильном направлении? Спасибо.


person Neilski    schedule 23.08.2011    source источник
comment
Создайте собственный тип ActionResult, как описано в этом сообщении: [stackoverflow.com/questions/989927/ [1]: stackoverflow.com/questions/ 989927/   -  person Bron Davies    schedule 28.05.2014
comment
Действительно выглядит как дубликат stackoverflow.com/q/943122/1178314 с неплохим ответом imho (stackoverflow.com/a/13456219/1178314)   -  person Frédéric    schedule 12.05.2015


Ответы (4)


Вчера я потратил некоторое время на аналогичную проблему, и вот как это сделать правильно:

public ActionResult CreateReport()
{
    var reportData = MyGetDataFunction();
    var serverPipe = new AnonymousPipeServerStream(PipeDirection.Out);
    Task.Run(() => 
    {
        using (serverPipe)
        {
             MyWriteDataToFile(reportData, serverPipe)
        }
    });

    var clientPipe = new AnonymousPipeClientStream(PipeDirection.In,
             serverPipe.ClientSafePipeHandle);
    return new FileStreamResult(clientPipe, "text/csv");
}
person galets    schedule 05.06.2015
comment
вы уверены в использовании (serverPipe)? он будет использоваться в FileStreamResult(clientPipe. Что произойдет, если задача запустится быстро? - person Slava; 18.09.2015
comment
Система @Slava будет управлять потоком данных между двумя концами трубы, так что это не должно вызывать беспокойства. Он не позволит задаче закрыть канал сервера, пока он не сможет использовать все данные. Другими словами, задача не завершится резко, она будет удерживаться либо при записи, либо при закрытии потока. Попробуйте, это работает. - person galets; 27.09.2015
comment
Каналы [AnonymousPipeClientStream] помогают обеспечить безопасную и надежную межпроцессную связь между дочерними и родительскими процессами. - кажется немного выше того, что требуется для выполнения одного и того же процесса. - person user2864740; 28.03.2019

Я нашел одно из возможных решений этой проблемы. Вы можете просто определить метод действия для возврата EmptyResult() и записи непосредственно в поток ответов. Например:

public ActionResult RobotsText() {
    Response.ContentType = "text/plain";
    Response.Write("User-agent: *\r\nAllow: /");
    return new EmptyResult();
}

Кажется, это работает без проблем. Не уверен, что это "MVC"...

person Neilski    schedule 02.09.2011
comment
Это взлом, контроллер MVC не должен писать напрямую в поток ответов. Предполагается, что это работа метода ExecuteResult объекта результата действия. - person Frédéric; 12.05.2015

Попробуйте вернуть один FileResults: http://msdn.microsoft.com/en-us/library/system.web.mvc.fileresult.aspx

Также см. этот пример: http://forums.asp.net/t/1491579.aspx/ 1

person Ofer Zelig    schedule 23.08.2011
comment
В настоящее время я использую что-то похожее с File(Encoding.UTF8.GetBytes(sb.ToString()), text/csv, fileName), но по-прежнему кажется потенциальной проблемой создание всего вывода в памяти перед фиксацией представления/ отклик. - person Neilski; 23.08.2011
comment
Исследуйте другие перегрузки File(). Пожалуйста, взгляните на ссылки, которые я разместил. Некоторые перегрузки не требуют создания файла в памяти. - person Ofer Zelig; 24.08.2011
comment
Разве построение массива байтов (byte[]) не завершает выходные данные в памяти перед их фиксацией в File ActionResult? Пример: return File(imageData,image/jpeg,fileName.jpg); - person Neilski; 24.08.2011
comment
Не понял вашего вопроса. - person Ofer Zelig; 24.08.2011
comment
Извините, Офер - спасибо за вашу настойчивость... В примерах, на которые вы ссылались, хранилище данных создает byte[], который затем передается методу File(), поэтому, я думаю, объект все еще создается/загружается в память до того, как он будет записан в представление. Я (думаю) искал что-то большее, чем возможность записывать необработанные данные в поток ответов. - person Neilski; 25.08.2011
comment
Нет - обратите внимание на 2 перегрузки File(), которые принимают путь к файлу, хранящемуся на вашем диске. Вы не создаете byte[] самостоятельно в этих перегрузках. - person Ofer Zelig; 25.08.2011

Попробуйте что-то вроде этого:

public ActionResult CreateReport(string report, string writer)
{
    var stream = new MemoryStream();
    var streamWriter = new StreamWriter(stream);

    _generateReport.GenerateReport(report, writer);

    streamWriter.Flush();
    stream.Seek(0, SeekOrigin.Begin);

    return new FileStreamResult(stream, writer.MimeType);
}
person cedd    schedule 02.10.2013
comment
Это полностью противоречит цели Streams. Пожалуйста, не делайте этого в производственном коде. - person makhdumi; 05.04.2017