Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 765
Adrian Avatar asked Jun 14 '16 21:06

Adrian


2 Answers

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.

like image 187
Adrian Avatar answered Nov 14 '22 23:11

Adrian


I guess you should set ContentDisposition and ContentType like this:

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

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(memStream.ToArray())
    };
    //this line
    result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "YourName.pdf"
    };
    //and this line
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    return result;
}
like image 42
teo van kot Avatar answered Nov 14 '22 22:11

teo van kot