Bagaimana cara mengembalikan PDF ke browser di MVC?

120

Saya memiliki kode demo ini untuk 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();

Bagaimana cara mendapatkan pengontrol untuk mengembalikan dokumen pdf ke browser?

EDIT:

Menjalankan kode ini tidak membuka Acrobat tetapi saya mendapatkan pesan kesalahan "File rusak dan tidak dapat diperbaiki"

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

Ada ide mengapa ini tidak berhasil?

Tony Borf
sumber
@ mg1075 link Anda sudah mati
thecoolmacdude

Jawaban:

128

Kembalikan a FileContentResult. Baris terakhir dalam tindakan pengontrol Anda akan menjadi seperti ini:

return File("Chap0101.pdf", "application/pdf");

Jika Anda membuat PDF ini secara dinamis, mungkin lebih baik menggunakan a MemoryStream, dan membuat dokumen di memori daripada menyimpannya ke file. Kodenya akan seperti ini:

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");
Geoff
sumber
@Tony, Anda harus menutup dokumen terlebih dahulu dan mengosongkan streaming.
Geoff
2
Geoff, saya mencoba untuk mencapai ini, tetapi mengalami masalah serupa. Saya mendapatkan kesalahan pada saat menjalankan "Tidak dapat mengakses Aliran yang ditutup" Tetapi jika saya tidak menutupnya tidak ada yang dikembalikan.
littlechris
1
Terima kasih @littlechris. Anda benar, saya telah mengedit kode menjadi pdfWriter.CloseStream = false;
Geoff
1
Ya @Geoff stream.Possition = 0; diperlukan, jika Anda tidak menulisnya, pada saat membuka PDF Acrobat menampilkan kesalahan "File rusak"
Alberto León
3
Tidak dapat secara implisit mengonversi jenis 'System.Web.Mvc.FileStreamResult' menjadi 'System.Web.Mvc.FileContentResult'
CountMurphy
64

Saya membuatnya berfungsi dengan kode ini.

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");    
}
Tony Borf
sumber
Dokumen, PdfWriter, dan Paragraph tidak dikenali. Namespace apa yang akan ditambahkan?
michael
9
Saya sedikit khawatir tidak ada satu pun usingpernyataan dalam contoh apa pun yang dapat saya temukan ... Apakah tidak diperlukan di sini? Saya pikir Anda memiliki setidaknya 3 benda sekali pakai ...
Kobi
Ya, menggunakan pernyataan itu bagus. Jika ini adalah aplikasi produksi dengan lebih dari, katakanlah ... SATU orang menggunakannya, ini dapat menyebabkan masalah ...
vbullinger
7
FileSteamResult akan menutup aliran untuk Anda. Lihat jawaban ini stackoverflow.com/a/10429907/228770
Ed Spencer
Yang penting atur Position = 0. haha. terima kasih @TonyBorf
ThanhLD
23

Anda harus menentukan:

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

Untuk file yang akan dibuka langsung di browser alih-alih diunduh

Machinegon
sumber
Terima kasih! Saya mencari kemana-mana tentang bagaimana melakukan ini !!
Scottie
17

Jika Anda mengembalikan a FileResultdari metode tindakan Anda, dan menggunakan File()metode ekstensi pada pengontrol, melakukan apa yang Anda inginkan cukup mudah. Ada penggantian pada File()metode yang akan mengambil konten biner file, jalur ke file, atau file Stream.

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

Saya mengalami masalah serupa dan saya menemukan solusi. Saya menggunakan dua posting, satu dari tumpukan yang menunjukkan metode untuk kembali untuk diunduh dan satu lagi yang menunjukkan solusi yang berfungsi untuk ItextSharp dan 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
    // /programming/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");
}
littlechris.dll
sumber
Contoh Luar Biasa! Inilah yang saya cari! - Pete -
DigiOz Multimedia
2
Menggunakan? Menutup? Membuang? Menyiram? Siapa yang peduli dengan kebocoran memori?
vbullinger
3

Saya tahu pertanyaan ini sudah tua tetapi saya pikir saya akan membagikan ini karena saya tidak dapat menemukan yang serupa.

Saya ingin membuat tampilan / model saya seperti biasa menggunakan Razor dan menjadikannya sebagai Pdfs .

Dengan cara ini saya memiliki kendali atas presentasi pdf menggunakan keluaran html standar daripada mencari tahu bagaimana tata letak dokumen menggunakan iTextSharp.

Proyek dan kode sumber tersedia di sini dengan petunjuk instalasi nuget:

https://github.com/andyhutch77/MvcRazorToPdf

Install-Package MvcRazorToPdf
hutchonoid.dll
sumber
3

FileStreamResultpasti berhasil. Tetapi jika Anda melihat pada Microsoft Docs , itu mewarisi dari ActionResult -> FileResult, yang memiliki kelas turunan lain FileContentResult. Ini "mengirimkan konten file biner ke respons". Jadi kalau sudah punya byte[], sebaiknya gunakan FileContentResultsaja.

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

    return new FileContentResult(byteArray, "application/pdf");
}
Weihui Guo
sumber
2

Anda biasanya akan melakukan Response.Flush diikuti oleh Response.Close, tetapi untuk beberapa alasan perpustakaan iTextSharp sepertinya tidak menyukai ini. Data tidak berhasil masuk dan Adobe mengira PDF tersebut rusak. Tinggalkan fungsi Response.Close dan lihat apakah hasil Anda lebih baik:

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();
JML
sumber
2
HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");

Jika nama file dibuat secara dinamis, lalu bagaimana mendefinisikan nama file di sini, itu dihasilkan melalui panduan di sini.

SJLee
sumber
1

jika Anda mengembalikan data var-binary dari DB untuk menampilkan PDF di popup atau browser berarti ikuti kode ini: -

Lihat halaman:

@using (Html.BeginForm("DisplayPDF", "Scan", FormMethod.Post))
    {
        <a href="javascript:;" onclick="document.forms[0].submit();">View PDF</a>
    }

Pengontrol pindai:

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
        }
ethiraj
sumber