Adrian Adrian - 5 months ago 230
AngularJS Question

Angular/Web API 2 returns invalid or corrupt file with StreamContent or ByteArrayContent

I'm trying to return a file in a ASP.NET Web API Controller. This file is a dynamically-generated PDF saved in a MemoryStream.

The client (browser) receives the file successfully, but when I open the file, I see that all the pages are totally blank.

The thing is that if I take the same MemoryStream and write it to a file, this disk file is displayed correctly, so I assume that the problem is related to the file transfer via Web.

My controller looks like this:

[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);

memStream.Position = 0;
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(memStream.ToArray()); //OR: new StreamContent(memStream);
return result;
}


Just to try, if I write the stream to disk, it's displayed correctly:

[HttpGet][Route("export/pdf")]
public HttpResponseMessage ExportAsPdf()
{
MemoryStream memStream = new MemoryStream();
PdfExporter.Instance.Generate(memStream);

memStream.Position = 0;
using (var fs = new FileStream("C:\\Temp\\test.pdf", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
memStream.CopyTo(fs);
}

return null;
}


The differences are:


  • PDF saved on disk: 34KB

  • PDF transferred via web: 60KB (!)



If I compare both files contents, the main differences are:

File Differences

On the left is the PDF transferred via web; on the right, the PDF saved to disk.

Is there something wrong with my code?
Maybe something related to encodings?

Thanks!

Answer

Well, it turned out to be a client (browser) problem, not a server problem. I'm using AngularJS in the frontend, so when the respose was received, Angular automatically converted it to a Javascript string. In that conversion, the binary contents of the file were somehow altered...

Basically it was solved by telling Angular not to convert the response to a string:

$http.get(url, { responseType: 'arraybuffer' })
.then(function(response) {
    var dataBlob = new Blob([response.data], { type: 'application/pdf'});
    FileSaver.saveAs(dataBlob, 'myFile.pdf');
});

And then saving the response as a file, helped by the Angular File Saver service.