JP Damstra
JP Damstra

Reputation: 613

Fetch API Download File

I feel like I'm so close to getting this right.
In this example the file is 125 KB and of type image/png.

I have a C# controller method that constructs a HttpResponseMessage with a file as follows:

public async Task<HttpResponseMessage> Get(int id)
{
      var file = await _api.GetFileAsync(id);

      var httpResult = new HttpResponseMessage(HttpStatusCode.OK);
      httpResult.Content = new ByteArrayContent(file.Bytes);
      httpResult.Content.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
      httpResult.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
      {
        FileName = file.Name
      }; //attachment will force download
      return httpResult;
}

The raw file itself is kept in the byte[] of file.Bytes.

And here's a JavaScript function that calls it:

get(fileId, fileName) {
    return this.httpFetch.fetch(`${this.apiRoot}/v1/files/${fileId}`)
      .then(response => response.blob())
      .then(data => {
        if (window.navigator.msSaveOrOpenBlob)
          window.navigator.msSaveBlob(data);
        else {
          var link = document.createElement("a");
          link.href = window.URL.createObjectURL(data);
          link.download = fileName;
          document.body.appendChild(link); // Required for FF
          link.click();
        }
      });
  }

Here's a preview of the payload according to Chrome network tools. Seems kind of empty to me... enter image description here

The type and filename are correct and it does auto-download, but I end up with a file that's 336 bytes and unreadable.

What am I missing here?

More Info: httpFetch is a wrapper of fetch by Aurelia (aurelia-fetch-client). I'm using Aurelia as my front-end framework.

Upvotes: 2

Views: 4742

Answers (1)

JP Damstra
JP Damstra

Reputation: 613

I can't explain why my solution above didn't work, but some other tests have revealed that the problem is more likely than not in the back-end C# WebApi controller method as my payload can be seen missing... well... the file which is odd.

I've gone for a simpler solution, namely:

public async Task<IActionResult> Get(int id)
{
      var file = await _api.GetFileAsync(id);
      var obj = new
      {
        file.Name,
        file.ContentType,
        Base64String = Convert.ToBase64String(file.Bytes)
      };

      return new OkObjectResult(obj);
}

Notice how I'm returning an anonymous object with the name, content type and base64 string representation of the file. Pairing this with a solution on base64 to blob in JavaScript solves the problem nicely with minor alterations to the get JavaScript function:

let blob = this.base64toBlob(data.base64String, data.contentType);

var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
document.body.appendChild(link); // Required for FF
link.click();

resolve(blob);

Upvotes: 1

Related Questions