如何在 MVC 中返回 PDF 到浏览器?

我有一个 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");
}

知道为什么这个不管用吗?

238385 次浏览

您可以创建一个自定义类来修改内容类型并将文件添加到响应中。

Http://haacked.com/archive/2008/05/10/writing-a-custom-file-download-action-result-for-asp.net-mvc.aspx

返回一个 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");

如果从 action 方法返回一个 FileResult,并在控制器上使用 File()扩展方法,那么做您想做的事情非常容易。对 File()方法进行了重写,该方法将获取文件的二进制内容、文件的路径或 Stream

public FileResult DownloadFile()
{
return File("path\\to\\pdf.pdf", "application/pdf");
}

我用这个密码让它工作。

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");
}

我也遇到过类似的问题,我偶然发现了一个解决方案。我使用了两篇文章,一篇来自 ,它显示了返回下载的方法,另一篇来自 ,它显示了 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 stackoverflow for this bit
// https://stackoverflow.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");
}

你通常会做出反应。同花后有回应。很接近,但是由于某种原因,iTextSharp 库似乎并不喜欢这样。数据没有通过,Adobe 认为 PDF 已经损坏。省略回应。关闭功能,看看你的结果是否更好:

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();

我知道这个问题很古老,但我想我会分享这个,因为我找不到任何类似的东西。

我想创建我的视图/模型作为正常的 用剃刀和有他们的 以 PDF 格式呈现

通过这种方式,我可以使用标准的 html 输出来控制 pdf 表示,而不用考虑如何使用 iTextSharp 来布局文档。

这个项目和源代码可以在这里找到,并附上了 nuget 的安装说明:

Https://github.com/andyhutch77/mvcrazortopdf

Install-Package MvcRazorToPdf

您必须指定:

Response.AppendHeader("content-disposition", "inline; filename=file.pdf");
return new FileStreamResult(stream, "application/pdf")

使文件在浏览器中为 直接打开而不是 下载

如果您从 DB 返回 var-binary 数据以便在弹出窗口或浏览器上显示 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
}
HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");

如果文件名是动态生成的,那么如何在这里定义文件名,它是通过 guid 生成的。

FileStreamResult当然可以。但是如果你看看 微软文档,它继承自 ActionResult -> FileResult,它有另一个派生类 FileContentResult。它“将二进制文件的内容发送给响应”。因此,如果你已经有了 byte[],你应该只是使用 FileContentResult代替。

public ActionResult DisplayPDF()
{
byte[] byteArray = GetPdfFromWhatever();


return new FileContentResult(byteArray, "application/pdf");
}