Terence
Terence

Reputation: 662

MVC 5 Controller return PDF file doesn't work

I am trying to create a print PDF file for my project.

Here is my code

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult PrintPdf(SubmitReport model)
    {
        if (model == null)
        {
            throw new ArgumentNullException(nameof(SubmitReport));
        }

        var pdfModel = new PdfViewModel {HeaderImgUrl = AppDomain.CurrentDomain.BaseDirectory + @"Content\logo.jpg"};
        var pdfStream = new MemoryStream(PdfGenerator.PayrollConfirmPdf(pdfModel).ToArray());

        // TODO: what is the name of the pdf file?
        var filename = string.Concat("PayrollConfirmation", DateTime.Now.ToString("yyyyMMddHHmmss"), ".pdf");

        return File(pdfStream, "application/pdf", filename);            
    }

It seems everything works fine, but after the function return, nothing happen. I was expecting a PDF file open/download in my local machine. However, no pop-up show up (as if nothing happen).

Any ideas?

Thanks in advance.

Upvotes: 0

Views: 3262

Answers (1)

Tetsuya Yamamoto
Tetsuya Yamamoto

Reputation: 24957

Seems that this line messing up:

var pdfStream = new MemoryStream(PdfGenerator.PayrollConfirmPdf(pdfModel).ToArray());

This creates instance of MemoryStream from a byte array, which possibly FileResult starts reading from end of stream instead of beginning.

You can use one of 2 possible solutions below:

1) Convert MemoryStream from PayrollConfirmPdf method as byte array and return the PDF as FileContentResult:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult PrintPdf(SubmitReport model)
{
    // other stuff

    byte[] pdfStream;

    using (var stream = new MemoryStream())
    {
        // fill stream content from other source
        stream = PdfGenerator.PayrollConfirmPdf(pdfModel);
        pdfStream = stream.ToArray();
    }

    // TODO: what is the name of the pdf file?
    var filename = string.Concat("PayrollConfirmation", DateTime.Now.ToString("yyyyMMddHHmmss"), ".pdf");

    // FileContentResult
    return File(pdfStream, "application/pdf", filename);            
}

2) Return FileStreamResult with Seek method set to beginning of stream:

using (var stream = new MemoryStream())
{
    // fill stream content from other source
    // make sure that PayrollConfirmPdf return MemoryStream here!
    stream = PdfGenerator.PayrollConfirmPdf(pdfModel);

    // add this line when using memory stream
    // alternative 1: stream.Seek(0, 0);
    stream.Seek(0, SeekOrigin.Begin); 

    var filename = string.Concat("PayrollConfirmation", DateTime.Now.ToString("yyyyMMddHHmmss"), ".pdf");

    // FileStreamResult
    return File(stream, "application/pdf", filename);
}   

Note that you can use stream.Position = 0; to reset stream position if stream.Seek method doesn't work.

Side note:

Since MemoryStream implements IDisposable, you should use using statement to dispose the stream immediately.

Similar issues:

FileResult with MemoryStream gives empty result .. what's the problem?

Return file for Saving from HttpPost Asp.Net MVC method (if using AJAX POST to download the file)

Upvotes: 2

Related Questions