2

I have a ASP.NET MVC app with a controller action which is triggered by a button press on my view. The controller action in turn calls a ASP.NET Web API. The Web API calls a third, outside system and asks for a PDF to be created at a network location. The Web API then picks up the PDF from the network location, converts it into a byte array, and returns the byte array from the Web API.

I have verified the PDF is generated properly by the third party application. I went to the network location and could open the PDF successfully.

At this point, I am back in my original MVC controller action, with a byte array. I now need to return the byte array to the browser as a PDF file for direct download, versus opening the PDF file. I have found answers such as this suggesting using the WriteAllBytes method to write the file. In my case though, I don't want to write the file to disk but instead want to return the file as a download to the user.

Also, I am not sure if I need to decode the byte array in my MVC app before attempting to send to the user for download. Does the Web API encode it as Base64 when it returns it?

This is a simplified version of my Web API code:

public byte[] GetPdf (int accountNumber)
{
    string filePath = _outsideServiceManager.RequestPdfCreation(accountNumber);

    byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);

    return pdfBytes;
}

And this is a simplified version of my MVC controller action code. I am using the overload of the Controller.File method which accepts a byte array.

public ActionResult DownloadPdf (int accountNumber)
{
    byte[] pdfFileAsByteArray = _serviceManager.GetPdf(accountNumber);

    return File(pdfFileAsByteArray, "application/pdf", "AccountSummary.pdf");
}

Right now I do successfully pick up the PDF file, convert it to a byte array, and successfully receive it in the MVC app. It does directly download to the user's browser, but when you try to open it with a PDF reader it says that the PDF file is corrupted.

How should I construct this flow?

EDIT: One observation I made was that the byte array might be 26 kb in the Web API, but closer to 34 kb when it is retrieved in the MVC app. Does this indicate encoding that has to be undone before accessing the file?

Community
  • 1
  • 1
  • 1
    Shouldnt AccountSummary in your return line be AccountSummary.pdf – Bearcat9425 Nov 27 '15 at 19:50
  • Not an answer to your question, but you might want to czech out iTextSharp for PDF generation. – B. Clay Shannon-B. Crow Raven Nov 27 '15 at 19:56
  • @Bearcat9425 Sorry, I left that off the code sample. I updated it. Even with the extension, the PDF reader cannot read it, saying it is a corrupted file. –  Nov 27 '15 at 19:57
  • Ok so it appears to be in the PDF creation process. What you have there looks fairly good as far as a File Result. How are you generating the PDF? RDLC, iTextSharp? – Bearcat9425 Nov 27 '15 at 19:58
  • @Bearcat9425 That process is done by a third party application, which is out of my hands. But the PDF is generated successfully, as I have gone to the network location myself to verify. –  Nov 27 '15 at 19:59
  • Have you tried passing the file Path vs a ByteArray. File("FilePath","application/pdf","AccountSummary.pdf") File() is overloaded. I did this just now on a test and it works fine. – Bearcat9425 Nov 27 '15 at 20:06
  • @Bearcat9425 Yep, and it does work that way. However with our design, we would like to prevent the client, the MVC app, from going to the network location and retreiving the file itself. We would like that to be the responsibility of the service layer. –  Nov 27 '15 at 20:08

3 Answers3

1

As Chris mentioned in a comment, the issue was with the response from the WebAPI. The byte array was automatically being encoded as a Base64 string, so when I tried to use that byte array in the client without decoding it first, it didn't work.

What I had to do was change my MVC app code to use ReadAsStringAsync versus ReadAsByteArrayAsync.

Then I had to remove the first and last character of the string as extra quotation marks were inserted for some reason, which would cause my subsequent conversion attempt to fail.

After that, I just used Convert.FromBase64String to decode the string and convert it into a byte array. The PDF files are now viewable.

0

You need to add the extension to the filename parameter:

return File(pdfFileAsByteArray, "application/pdf", "AccountSummary");

should be

return File(pdfFileAsByteArray, "application/pdf", "AccountSummary.pdf");
Mike B
  • 5,390
  • 2
  • 23
  • 45
  • Sorry, I left that off the code sample. But I did try that in my actual code. The PDF Reader opens it but says it is corrupted. –  Nov 27 '15 at 19:56
  • 1
    There has to be something wrong with the contents of your byte array, then. This is exactly how we do it and it works fine. – Mike B Nov 27 '15 at 19:59
  • @mikew0633 Have you tested your PDF file generator code separately? This solution by Mike B should work, like he said, likely your byte array is corrupt. – Shiva Nov 27 '15 at 20:00
  • @MikeB I see. When you do it, do you worry about decoding the byte array received from the Web API? Or is it decoded automatically? –  Nov 27 '15 at 20:00
  • @Shiva Yes, I navigated to the network location where the files are housed and can open them successfully there. –  Nov 27 '15 at 20:01
  • 2
    @mikew0633 It's likely that the problem is with the WebApi binary response. For troubleshooting, could you try something like base64 encoding and decoding the bytes? If that works fine, you make want to treat the pdf file as a stream throughout the process. – Christopher Stevenson Nov 27 '15 at 20:38
0

I think what you'll need to do is have the WebApi response be a simple HttpResponseMessage, with a StreamContent inside. Then you can simply have MVC return the stream.

Community
  • 1
  • 1
Christopher Stevenson
  • 2,843
  • 20
  • 25