Вывод Response.Stream (PDF) потерян Adobe Reader - PullRequest
0 голосов
/ 24 февраля 2010

В приложении ASP.NET я использую iTextSharp (в основном PdfStamper), чтобы заполнить некоторый контент в PDF и отправить его пользователю. Следующий код находится внутри события OnClick:

PdfReader r = new PdfReader(
  new RandomAccessFileOrArray(Request.MapPath(compatiblePdf)), null
);

ps = new PdfStamper(r, Response.OutputStream);
AcroFields af = ps.AcroFields;

af.SetField("ContactInfo[0]", o.mallName);
af.SetField("ClientName", string.Format("{0} {1}", c.firstName, c.lastName));
af.SetField("ClientEmail", c.emailAddress);
ps.FormFlattening = true;
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment; filename=Form.pdf");
ps.Close();
Response.End();

Таким образом, в основном PdfReader получает файл, PdfStamper принимает PdfReader в качестве аргумента и отправляет законченный PDF в Response.OutputStream.

Проблема в том, что в IE и Adobe Reader, если вы выбираете «Открыть» в диалоговом окне файла, Adobe Reader выдает ошибку, говорящую «файл не найден». Пользователи могут "сохранить" файл просто отлично, и даже запуск загрузки снова (повторное нажатие кнопки "Открыть" при запросе), кажется, работает. Но на новом компьютере, который никогда не загружал файл, Adobe Reader, похоже, неправильно помещает файл между тем, что он делает, к временным файлам или чем-то еще, что делает IE.

Я могу сейчас представить только одну вещь: Response.End(), может быть, может быть Response.Close() вместо этого, или, может быть, все это должно иметь Response.Flush() перед ним. Но я точно не знаю, что это не усугубит проблему, и я испытываю трудности с тестированием (потому что, как только вы скачали файл один раз, ошибка больше не выдается).

Может, это решит проблему? У меня что-то не так в заголовках? Или я должен что-то еще сделать с объектами Response / PdfStamper?

1 Ответ

5 голосов
/ 24 февраля 2010

Всякий раз, когда я навязываю контент пользователю, я выполняю этот набор шагов для ответа:

Response.Clear()
Response.ClearHeaders()
Response.Buffer = True
Response.ContentType = "your mime type"
Response.CacheControl = "public"
Response.AddHeader("Pragma", "public")
Response.AddHeader("Expires", "0")
Response.AddHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0")
Response.AddHeader("Content-Description", "Description of your content")
Response.AddHeader("Content-Disposition", "attachment; filename=""somefile.pdf""")

' Add your content to the buffer here

Response.Flush()
Response.End()

Кажется, это очень хорошо предотвращает весь мусор "файл не найден".

РЕДАКТИРОВАТЬ: Для тех, кто интересуется, что на самом деле означают эти заголовки:

  1. Pragma: public помогает контролировать кэш для обратной совместимости с запросами HTTP / 1.0. Это гарантирует, что ваш запрос поступит на сервер, даже если уже есть кэшированный ответ.
  2. Expires: 0 - интервал в секундах, после которого истекает срок ответа. Установка в 0 немедленно истекает ответ, помогая избежать устаревшего кэша.
  3. Cache-control: must-revalidate сообщает кешу, что он должен подчиняться каждой вашей команде (т. Е. Он должен давать вам новый ответ, когда вы его просите).
  4. Cache-control: post-check=0, pre-check=0: это интервал в секундах, в течение которого ответ должен проверяться на свежесть после / до (соответственно) подачи содержимого. Установка в 0 заставляет свежесть ответа проверяться немедленно. ( Больше на MSDN .)
  5. Остальные просто описывают контент, который вы хотите получить от пользователя. Указание «вложения» указывает браузеру предлагать файл для загрузки и не отображать его в строке.
...