3

Using a FileStreamResult from C# in a SPA website (.NET Core 2, SPA React template), I request a file from my endpoint, which triggers this response in C#:

var file = await _docService.GetFileAsync(token.UserName, instCode.Trim()
.ToUpper(), fileSeqNo);
string contentType = MimeUtility.GetMimeMapping(file.FileName);
var result = new FileStreamResult(file.File, contentType);
var contentDisposition = new ContentDispositionHeaderValue("attachment");
Response.Headers[HeaderNames.ContentDisposition] = 
contentDisposition.ToString();
return result;

The returned response is handled using msSaveBlob (spesificly for MS, but this is a problem even though I use createObjectURL and different browser (Yes, I have tried multiple solutions to this, but none of them seems to work). This is the code I use to send the request, and receive the PDF FileStreamResult from the server.

if (window.navigator.msSaveBlob) {
  axios.get(url).then(response => {
      window.navigator.msSaveOrOpenBlob(
          new Blob([response.data], {type: "application/pdf"}),
          filename);
  });

The problem is that the returned PDF file that I get has a wrong encoding on it somehow. So the PDF will not open.

I have tried adding encoding to the end of type: {type: "application/pdf; encoding=UTF-8"} which was suggested in different posts, however, it makes no difference.

Comparing a PDF file that I have fetched in a different way, I can clearly see that the encoding is wrong. Most of the special characters are not correct. Indicated by the response header, the PDF file should be in UTF-8, but I have no idea how to actually find out and check.

Keshav Pradeep Ramanath
  • 1,623
  • 4
  • 24
  • 33
Thomas Darvik
  • 748
  • 7
  • 22
  • A PDF is a binary file and as such has no encoding (as far as mime types are concerned). It MUST NOT be changed by treating it as textual data (which is subject to encodings). – mkl Mar 06 '18 at 16:28
  • So you're saying I should remove the contentType where I use the MimeMapping? – Thomas Darvik Mar 06 '18 at 16:54
  • The mime type "application/pdf" does not allow for an encoding parameter. But some software might be tricked into applying an encoding nonetheless and so damage the PDF. I don't know whether using "application/pdf" with an encoding parameter is the *cause* of your base problem, but trying to *solve* the problem with such an encoding parameter is wrong. And if you try it and some encoding value indeed helps, then the other side of the transfer effectively makes the same error und you merely have two errors cancelling each other out which would be a very unstable situation to keep... – mkl Mar 06 '18 at 17:12
  • Ok, can you think of a place where the data is encoded to the wrong format, i.e destroying the pdf file? Is it in the controller/service (backend), transfer layer to the client or in the client? Any help is greatly appreciated as I am really stuck. – Thomas Darvik Mar 06 '18 at 20:59

1 Answers1

10

Without knowing axios it seems though from its readme page that it uses JSON as default responseType. This may potentially alter the content as it is now treated as text (axios will probably bail out when it cannot convert to an actual JSON object and keep the string/text source for response data).

A PDF should be loaded as binary data even though it can be both, either 8-bit binary content or 7-bit ASCII - both should in any case be treated as a byte stream, from Adobe PDF reference sec. 2.2.1:

PDF files are represented as sequences of 8-bit binary bytes. A PDF file is designed to be portable across all platforms and operating systems. The binary rep resentation is intended to be generated, transported, and consumed directly, without translation between native character sets, end-of-line representations, or other conventions used on various platforms. [...].

Any PDF file can also be represented in a form that uses only 7-bit ASCII [...] character codes. This is useful for the purpose of exposition, as in this book. However, this representation is not recommended for actual use, since it is less efficient than the normal binary representation. Regardless of which representation is used, PDF files must be transported and stored as binary files, not as text files. [...]

So to solve the conversion that happens I would suggest trying specifying the configuration entry responseType when doing the request:

axios.get(url, {responseType: "arraybuffer"}) ...

or in this form:

axios({
  method: 'get',
  url: url,
  responseType:'arraybuffer'
})
.then( ... )

You can also go directly to response-type blob if you are sure the mime-type is preserved in the process.

  • 4
    Correct. This is the correct way of handling it. The problem was that the PDF was just bytes, however, while transferring the PDF file, it got treated as something else. – Thomas Darvik Mar 08 '18 at 15:02
  • I first tried setting response-type to blob, but it didn't work. responseType:'arraybuffer' worked for me. Thank you ! – Milan Raval Oct 17 '18 at 16:22