Как вернуть PDF в браузер в MVC?
У меня есть этот демо-код для iTextSharp
Document document = new Document();
try
{
PdfWriter.GetInstance(document, new FileStream("Chap0101.pdf", FileMode.Create));
document.Open();
document.Add(new Paragraph("Hello World"));
}
catch (DocumentException de)
{
Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
Console.Error.WriteLine(ioe.Message);
}
document.Close();
Как мне заставить контроллер вернуть PDF документ в браузер?
РЕДАКТИРОВАТЬ:
Запуск этого кода открывает Acrobat, но я получаю сообщение об ошибке "Файл поврежден и не может быть восстановлен"
public FileStreamResult pdf()
{
MemoryStream m = new MemoryStream();
Document document = new Document();
PdfWriter.GetInstance(document, m);
document.Open();
document.Add(new Paragraph("Hello World"));
document.Add(new Paragraph(DateTime.Now.ToString()));
m.Position = 0;
return File(m, "application/pdf");
}
Есть идеи, почему это не работает?
10 ответов
Я получил это работает с этим кодом.
using iTextSharp.text;
using iTextSharp.text.pdf;
public FileStreamResult pdf()
{
MemoryStream workStream = new MemoryStream();
Document document = new Document();
PdfWriter.GetInstance(document, workStream).CloseStream = false;
document.Open();
document.Add(new Paragraph("Hello World"));
document.Add(new Paragraph(DateTime.Now.ToString()));
document.Close();
byte[] byteInfo = workStream.ToArray();
workStream.Write(byteInfo, 0, byteInfo.Length);
workStream.Position = 0;
return new FileStreamResult(workStream, "application/pdf");
}
Вернуть FileContentResult
, Последняя строка в вашем контроллере будет выглядеть примерно так:
return File("Chap0101.pdf", "application/pdf");
Если вы генерируете этот PDF-файл динамически, лучше использовать MemoryStream
и создать документ в памяти вместо сохранения в файл. Код будет что-то вроде:
Document document = new Document();
MemoryStream stream = new MemoryStream();
try
{
PdfWriter pdfWriter = PdfWriter.GetInstance(document, stream);
pdfWriter.CloseStream = false;
document.Open();
document.Add(new Paragraph("Hello World"));
}
catch (DocumentException de)
{
Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
Console.Error.WriteLine(ioe.Message);
}
document.Close();
stream.Flush(); //Always catches me out
stream.Position = 0; //Not sure if this is required
return File(stream, "application/pdf", "DownloadName.pdf");
Вы должны указать:
Response.AppendHeader("content-disposition", "inline; filename=file.pdf");
return new FileStreamResult(stream, "application/pdf")
Чтобы файл открывался прямо в браузере, а не загружался
Если вы вернете FileResult
от вашего метода действия, и используйте File()
метод расширения на контроллере, делать то, что вы хотите, довольно легко. Есть переопределения на File()
метод, который будет принимать двоичное содержимое файла, путь к файлу или Stream
,
public FileResult DownloadFile()
{
return File("path\\to\\pdf.pdf", "application/pdf");
}
Я столкнулся с подобными проблемами, и я наткнулся на решение. Я использовал две публикации: одна из стека, в которой показан метод возврата для загрузки, а другая - рабочее решение для ItextSharp и MVC.
public FileStreamResult About()
{
// Set up the document and the MS to write it to and create the PDF writer instance
MemoryStream ms = new MemoryStream();
Document document = new Document(PageSize.A4.Rotate());
PdfWriter writer = PdfWriter.GetInstance(document, ms);
// Open the PDF document
document.Open();
// Set up fonts used in the document
Font font_heading_1 = FontFactory.GetFont(FontFactory.TIMES_ROMAN, 19, Font.BOLD);
Font font_body = FontFactory.GetFont(FontFactory.TIMES_ROMAN, 9);
// Create the heading paragraph with the headig font
Paragraph paragraph;
paragraph = new Paragraph("Hello world!", font_heading_1);
// Add a horizontal line below the headig text and add it to the paragraph
iTextSharp.text.pdf.draw.VerticalPositionMark seperator = new iTextSharp.text.pdf.draw.LineSeparator();
seperator.Offset = -6f;
paragraph.Add(seperator);
// Add paragraph to document
document.Add(paragraph);
// Close the PDF document
document.Close();
// Hat tip to David for his code on stackru for this bit
// https://stackru.com/questions/779430/asp-net-mvc-how-to-get-view-to-generate-pdf
byte[] file = ms.ToArray();
MemoryStream output = new MemoryStream();
output.Write(file, 0, file.Length);
output.Position = 0;
HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");
// Return the output stream
return File(output, "application/pdf"); //new FileStreamResult(output, "application/pdf");
}
FileStreamResult
конечно работает. Но если вы посмотрите на документы Microsoft, он наследует от ActionResult -> FileResult
, который имеет другой производный класс FileContentResult
, Он "отправляет содержимое двоичного файла в ответ". Так что, если у вас уже есть байт [], вы должны просто использовать FileContentResult
вместо.
public ActionResult DisplayPDF()
{
byte[] byteArray = GetPdfFromWhatever();
return new FileContentResult(byteArray, "application/pdf");
}
Я знаю, что этот вопрос старый, но я подумал, что поделюсь этим, потому что не смог найти ничего похожего.
Я хотел создать мои представления / модели как обычно, используя Razor и сделать их в формате PDF.
Таким образом, я управлял презентацией PDF, используя стандартный вывод html, вместо того, чтобы выяснить, как оформить документ с помощью iTextSharp.
Проект и исходный код доступны здесь с инструкциями по установке nuget:
https://github.com/andyhutch77/MvcRazorToPdf
Install-Package MvcRazorToPdf
Вы можете создать собственный класс, чтобы изменить тип содержимого и добавить файл в ответ.
Обычно вы выполняете Response.Flush, за которым следует Response.Close, но по какой-то причине библиотека iTextSharp, похоже, не нравится. Данные не передаются, и Adobe считает, что PDF поврежден. Оставьте функцию Response.Close и посмотрите, будут ли ваши результаты лучше:
Response.Clear();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-disposition", "attachment; filename=file.pdf"); // open in a new window
Response.OutputStream.Write(outStream.GetBuffer(), 0, outStream.GetBuffer().Length);
Response.Flush();
// For some reason, if we close the Response stream, the PDF doesn't make it through
//Response.Close();
HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");
если имя файла генерируется динамически, то как определить имя файла здесь, оно генерируется через guid здесь.
если вы возвращаете двоичные данные var из БД для отображения PDF во всплывающем окне или браузере, следуйте этому коду:-
Просмотр страницы:
@using (Html.BeginForm("DisplayPDF", "Scan", FormMethod.Post))
{
<a href="javascript:;" onclick="document.forms[0].submit();">View PDF</a>
}
Контроллер сканирования:
public ActionResult DisplayPDF()
{
byte[] byteArray = GetPdfFromDB(4);
MemoryStream pdfStream = new MemoryStream();
pdfStream.Write(byteArray, 0, byteArray.Length);
pdfStream.Position = 0;
return new FileStreamResult(pdfStream, "application/pdf");
}
private byte[] GetPdfFromDB(int id)
{
#region
byte[] bytes = { };
string constr = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "SELECT Scan_Pdf_File FROM PWF_InvoiceMain WHERE InvoiceID=@Id and Enabled = 1";
cmd.Parameters.AddWithValue("@Id", id);
cmd.Connection = con;
con.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
if (sdr.HasRows == true)
{
sdr.Read();
bytes = (byte[])sdr["Scan_Pdf_File"];
}
}
con.Close();
}
}
return bytes;
#endregion
}