0

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.

Terence
  • 652
  • 11
  • 34
  • Check output of `pdfStream`, is that returns byte array containing PDF file? Also try this: `var pdfStream = new MemoryStream(PdfGenerator.PayrollConfirmPdf(pdfModel)).ToArray();`. – Tetsuya Yamamoto Apr 26 '18 at 01:47
  • @TetsuyaYamamoto Yes, I forced it to be byte array: `byte[] pdfStream; var stream = new MemoryStream(); using (stream) { stream = PdfGenerator.PayrollConfirmPdf(pdfModel); pdfStream = stream.ToArray(); }` The problem still there. – Terence Apr 26 '18 at 18:47

1 Answers1

2

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)

Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61
  • Thank you for your answer, I tried to use the IDisposable. I got an error: `"Severity Code Description Project File Line Suppression State Error CS1656 Cannot assign to 'stream' because it is a 'using variable'"` – Terence Apr 26 '18 at 18:20
  • Once again, thank you for your detailed answer. I also tried your solution #1. I can verify that the steam has content. However, it still behaves the same. The same problem still there. – Terence Apr 26 '18 at 18:38
  • I dug a little bit. The main problem is in the front-end. Because I am using an AJAX post, and the pdf file is successfully generated. I just need to let the front-end grab the file. – Terence Apr 26 '18 at 20:45
  • If you're using AJAX POST, then you should use `success` block to ensure that the response received and use `window.location.href` to redirect into GET action method which returns `FileResult` (AJAX primarily used to sending request while stay on same page). – Tetsuya Yamamoto Apr 27 '18 at 00:48