Длительный процесс, который вернет файл - PullRequest
8 голосов
/ 25 августа 2009

Я использую ASP.NET MVC и у меня длительный процесс. В частности, я создаю большой PDF для загрузки пользователем.

Я понимаю основную концепцию:

  1. Метод действия вызывается
  2. Новый поток начал генерировать процесс
  3. Возвращает представление, которое сообщает пользователю, что (pdf) генерируется
  4. Используйте AJAX для вызова сервера и запроса прогресса
  5. По завершении предоставьте файл пользователю для загрузки.

Части, которые я не до конца понимаю:

  • Управление потоком через отдельные вызовы AJAX. Возможно, мне понадобится какой-нибудь способ найти работающий поток и запросить статус. Есть ли статический контекст, в котором я могу сохранить ссылку на поток? Мне известно о кешировании данных в HttpContext.Application, подойдет ли это для этого?
  • А как представить готовый файл. Создать временный файл и представить ссылку для скачивания? Или я могу сделать последний AJAX-вызов, который возвращает файл?

Ответы [ 2 ]

7 голосов
/ 25 августа 2009

Работает!

Вот что я сделал:

Шаг 1 и 2 - вызывается метод действия, запущен длительный поток

Когда вызывается мой метод действия, он генерирует уникальный идентификатор. Затем я создаю экземпляр моего класса PdfGenerator, создаю новый поток с именем PdfGenerator.Generate и запускаю его.

public class PdfGenerator
{
    public string State;
    public byte[] Data;

    public void Generate()
    {
        // Generate PDF/Long running process
        // Should update State as it goes
        // ...
        // Once finished, Data is populated with the binary byte[]
    }
}

После запуска потока (или до его запуска) экземпляр генератора сохраняется в кеше:

HttpContext.Cache[guid] = generator;

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

Шаг 3 и 4 - Отображение и обновление статуса / просмотр хода выполнения

Теперь, когда поток запущен и началась генерация PDF, я могу отобразить свой сценарий просмотра прогресса. Используя jQuery $.getJSON, я могу опросить отдельное действие, чтобы узнать статус генерации:

[OutputCache(Duration = 0, VaryByName = "none", NoStore = true)]
public JsonResult CheckPdfGenerationStatus(string guid)
{
    // Get the generator from cache
    var generator = HttpContext.Cache[guid] as PdfGenerator;

    if (generator == null)
        return Json(null);
    else
        return Json(generator.State);
}

Мой скрипт просмотра интерпретирует Json и отображает соответствующую информацию о прогрессе.

Шаг 5 - представить файл пользователю

Как только генерация завершена, состояние генераторов устанавливается соответствующим образом, и когда jQuery получает эту информацию, он может либо сделать доступной ссылку, либо напрямую отправить файл, используя javascripts location.href.

Метод Action, который устанавливает и возвращает файл, просто извлекает генератор из кэша и возвращает присоединенный байт []

public ContentResult DownloadPdf(string guid)
{
    var generator = HttpContext.Cache[guid] as PdfGenerator;

    if (generator == null)
        return Content("Error");

    if (generator.State == "Completed")
    {
        return Content(generator.Data);
    }
    else
    {
        return Content("Not finished yet");
    }
}

Моя настоящая работа У меня есть более подробное состояние, такое как Инициализировано, Работает и Завершено. А также процент выполнения (в десятичном виде, 1,0 завершено).

Так что, да, надеюсь, это поможет кому-то еще, пытающемуся сделать что-то подобное.

6 голосов
/ 25 августа 2009

Кеш очень хорошо подходит для этого. Только одна вещь - убедиться, что кэшированный элемент никогда не удаляется во время выполнения процесса (для этого вы можете использовать ItemPriority.NotRemovable).

Вы можете сохранить файл на диске во временной папке или в течение некоторого времени (в зависимости от ситуации). Лично я не хочу загрязнять жесткий диск файлами, чтобы сохранить файл в кеше (с MediumPriority в течение нескольких минут). Но размер файла велик и может быть сгенерирован часто, вместо этого рекомендуется использовать базу данных файловой системы.

На клиенте, когда последний Ajax-запрос возвращает результат (может выглядеть как {progress: "100%", resultUrl: "http://your.url/Where/ToGet/TheFile.aspx?file=GUID-OR-CACHE-KEY"}), вы можете перенаправить браузер на указанный URL-адрес.
Это, в свою очередь, отобразит этот файл как двоичный результат.

Перенаправление клиента может быть выполнено с использованием Javascript следующим образом:

location.href = response.resultUrl;

Кстати, как вы генерируете PDF? NFOP

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...