Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to download binary file using ASP.net Web API and Javascript?

I have a Web API controller that looks like this:

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;
using System.Threading.Tasks;
using System.IO;

    namespace APIIntegration.Controllers
    {
        public class TestController : ApiController
        {
            // http://localhost/api/test
            [HttpGet]        
            public async Task<HttpResponseMessage> Get()
            {
                Stream stream = streamWith256Bytes;            
                HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);            
                result.Content = new StreamContent(stream);
                result.Content.Headers.ContentLength = stream.Length;            
                result.Content.Headers.ContentType =
                    new MediaTypeHeaderValue("application/octet-stream");
                result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
                result.Content.Headers.ContentDisposition.FileName = "foo.bin";
                return result;
            }

            private static Stream streamWith256Bytes
            {
                get
                {
                    MemoryStream stream = new MemoryStream();
                    for (int i = 0; i <256 ; i++)
                    {
                        stream.WriteByte(Convert.ToByte(i));
                    }
                    stream.Position = 0;
                    return stream;
                }
            }
        }
    }

In short, this controller attempts to download a 256 byte file to the browser. At first, it appears to work, but when the downloaded file is examined, the size is 512 bytes instead of the expected 256 bytes and the non-printable characters are trashed.

How can I modify this code so that binary data may be downloaded correctly?

Edit: I should also mention that I saw a similar question here: Problems with downloading pdf file from web api service where the problem was fixed by adding a content-length header, but that didn't solve this for me.

Edit: I modified the source code above to give a complete, working example of how to reproduce.

Edit: I've discovered that the above code actually works correctly when I key in the address in the address bar, but when using Javascript to initiate the download, that's where I'm having a problem.

like image 849
Vivian River Avatar asked Sep 27 '22 06:09

Vivian River


1 Answers

I have found a solution. In my Javascript, I used Angular to initiate a file download using the Angular $http service. By default, this service interprets the response as text. I had to tell Angular to interpret the response as a blob, and that fixed everything.

My working code looks like this:

function download(downloadUrl) {
    $http({
        url: downloadUrl,
        responseType: "blob"
    })
    .then(function (response) {
        var blob = new Blob([response.data], { type: "application/octet-stream" });
        saveAs(blob, "foo.bin");
    }, function (response) {
        alert("error downloading file from " + downloadUrl);
    });
}
like image 157
Vivian River Avatar answered Oct 11 '22 09:10

Vivian River