จะคืน PDF ไปยังเบราว์เซอร์ใน MVC ได้อย่างไร


120

ฉันมีรหัสสาธิตสำหรับ 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");
    }

มีความคิดว่าเหตุใดจึงใช้ไม่ได้?



1
@ mg1075 ลิงก์ของคุณตายแล้ว
thecoolmacdude

คำตอบ:


128

กลับกFileContentResult. บรรทัดสุดท้ายในการทำงานของคอนโทรลเลอร์ของคุณจะเป็นดังนี้:

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

หากคุณกำลังสร้าง PDF นี้แบบไดนามิกอาจเป็นการดีกว่าที่จะใช้ a 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");

@ โทนี่คุณต้องปิดเอกสารก่อนแล้วล้างสตรีม
Geoff

2
Geoff ฉันพยายามที่จะบรรลุสิ่งนี้ แต่มีปัญหาที่คล้ายกัน ฉันได้รับข้อผิดพลาดขณะทำงาน "ไม่สามารถเข้าถึงสตรีมแบบปิด" แต่ถ้าฉันไม่ปิดก็จะไม่มีการส่งคืน
littlechris

1
ขอบคุณ @littlechris คุณพูดถูกฉันได้แก้ไขโค้ดเป็น pdfWriter.CloseStream = false;
Geoff

1
ใช่ @Geoff stream.Possition = 0; เป็นสิ่งจำเป็นหากคุณไม่ได้เขียนในขณะที่เปิด PDF Acrobat แสดงข้อผิดพลาด "ไฟล์เสียหาย"
Alberto León

3
ไม่สามารถแปลงประเภท 'System.Web.Mvc.FileStreamResult' เป็น 'System.Web.Mvc.FileContentResult' โดยปริยาย
CountMurphy

64

ฉันทำให้มันใช้งานได้กับรหัสนี้

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

ไม่รู้จักเอกสาร, PdfWriter และย่อหน้าจะเพิ่มเนมสเปซอะไร
michael

9
ฉันกังวลเล็กน้อยไม่มีusingคำสั่งใด ๆ ในตัวอย่างที่ฉันสามารถหาได้ ... มันไม่จำเป็นที่นี่หรือ? ฉันคิดว่าคุณมีของใช้แล้วทิ้งอย่างน้อย 3 ชิ้น ...
Kobi

ใช่การใช้งบจะดี หากเป็นแอปที่ใช้งานจริงมากกว่าให้พูดว่า ... มีคนใช้งานเพียงคนเดียวอาจทำให้เกิดปัญหาได้ ...
vbullinger

7
FileSteamResult จะปิดสตรีมให้คุณ ดูคำตอบนี้stackoverflow.com/a/10429907/228770
Ed Spencer

ที่สำคัญคือตั้ง Position = 0. ฮ่าฮ่า ขอบคุณค่ะ @TonyBorf
ThanhLD

23

คุณต้องระบุ:

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

สำหรับไฟล์ที่จะเปิดโดยตรงในเบราว์เซอร์แทนที่จะดาวน์โหลด


ขอบคุณ! ผมตามหาทุกที่ว่าจะทำยังไง !!
Scottie

17

หากคุณส่งคืน a FileResultจากวิธีการดำเนินการของคุณและใช้File()วิธีการขยายบนคอนโทรลเลอร์การทำสิ่งที่คุณต้องการนั้นค่อนข้างง่าย มีการลบล้างFile()วิธีการที่จะใช้เนื้อหาไบนารีของไฟล์เส้นทางไปยังไฟล์หรือไฟล์Stream.

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

11

ฉันพบปัญหาที่คล้ายกันและฉันพบวิธีแก้ปัญหา ฉันใช้สองโพสต์หนึ่งรายการจากสแต็กที่แสดงวิธีการส่งคืนสำหรับการดาวน์โหลดและอีกรายการหนึ่งที่แสดงโซลูชันการทำงานสำหรับ 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
    // /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");
}

ตัวอย่างยอดเยี่ยม! นี่คือสิ่งที่ฉันกำลังมองหา! - Pete -
DigiOz Multimedia

2
Usings? ปิด? ทิ้ง? ฟลัช? ใครสนใจเรื่องความจำรั่ว
vbullinger

3

คุณสามารถสร้างคลาสแบบกำหนดเองเพื่อแก้ไขชนิดเนื้อหาและเพิ่มไฟล์ในการตอบกลับ

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


7
ตามที่ระบุไว้ที่ด้านบนของบล็อกโพสต์นั้น FileResult มาพร้อมกับ Asp.Net MVC ดังนั้นการเข้ารหัสของคุณเองจึงไม่จำเป็นอีกต่อไป
NerdFury

3

ฉันรู้ว่าคำถามนี้เก่า แต่ฉันคิดว่าฉันจะแบ่งปันสิ่งนี้เพราะฉันไม่พบอะไรที่คล้ายกัน

ฉันต้องการสร้างมุมมอง / แบบจำลองของฉันตามปกติโดยใช้ Razorและให้พวกเขาแสดงผลเป็น Pdfsกลายเป็นไฟล์ PDF

ด้วยวิธีนี้ฉันสามารถควบคุมการนำเสนอ pdf โดยใช้เอาต์พุต html มาตรฐานแทนที่จะหาวิธีจัดเค้าโครงเอกสารโดยใช้ iTextSharp

โครงการและซอร์สโค้ดมีอยู่ที่นี่พร้อมคำแนะนำการติดตั้ง nuget:

https://github.com/andyhutch77/MvcRazorToPdf

Install-Package MvcRazorToPdf

3

FileStreamResultได้ผลอย่างแน่นอน แต่ถ้าคุณมองไปที่ไมโครซอฟท์เอกสารก็สืบทอดจากซึ่งมีชั้นเรียนมาอีกActionResult -> FileResult FileContentResultมัน "ส่งเนื้อหาของไฟล์ไบนารีไปยังการตอบกลับ" ดังนั้นหากคุณมีอยู่แล้วbyte[]คุณควรใช้FileContentResultแทน

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

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

2

โดยปกติคุณจะตอบกลับ 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();

2
HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");

หากชื่อไฟล์ถูกสร้างขึ้นแบบไดนามิกวิธีกำหนดชื่อไฟล์ที่นี่จะสร้างผ่าน guid ที่นี่


1

หากคุณส่งคืนข้อมูล var-binary จาก DB เพื่อแสดง 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
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.