0

I am currently attempting to download a Word document from my angular 5 application. The docx file sits in a template folder on the server, and it opens without a problem from the server. But when I retrieve it in my application, send it to the client, and then call saveAs to download it, it downloads, but the file opens corrupted. I have had a look at a whole bunch of other issues but haven't come across one that covers this scenario. I suspect it might be some sort of encoding issue.

In my controller, the code looks like this:

[HttpGet("[action]")]
public IActionResult GetGdwFile([FromBody] int gdwQueryJobId)
{
   var currentDirectory = Directory.GetCurrentDirectory();
   var filePath = Path.Combine(currentDirectory, @"DocumentTemplates\nab.docx");
   var fileData = System.IO.File.ReadAllBytes(filePath);
   return Ok(new Models.APIResult {Success = true, Data = fileData});
}

Within the angular client side code, my call looks like this:

downloadFile() {
        this.gdwService.getGdwFile(1).subscribe(response => {
            const fileBlob = new Blob([response.data], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" });
            saveAs(fileBlob, "Salesbypostcode.docx");
        });
    }

When I debug, response.data does contain the full binary data array, as expected.

The gdwservice call is just a straight through http get:

getGdwFile(gdwQueryJobId: number) {

   return this.http.get(`/api/Gdw/getGdwPdfFile?gdwQueryJobId=${gdwQueryJobId}`,
        {
            headers: new HttpHeaders({
                "Content-Type": "application/json",
            })
        });
}

What do I need to do to get this downloading properly without the file turning up corrupted?

tone
  • 1,374
  • 20
  • 47

2 Answers2

2

Ok, I've found an answer to my problem. When the data is returned from the service method, it doesn't appear to be encoded properly. To solve that, I did the following:

downloadGdwFile() {
        this.gdwService.getGdwFile(1).subscribe(response => {
            const byteCharacters = atob(response.data);
            var byteNumbers = new Array(byteCharacters.length);
            for (let i = 0; i < byteCharacters.length; i++) {
                byteNumbers[i] = byteCharacters.charCodeAt(i);
            }
            var byteArray = new Uint8Array(byteNumbers);
            var blob = new Blob([byteArray], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" });
            saveAs(blob, "Salesbypostcode.docx");
        });
    }

I got the idea from the answer of this stack overflow issue

You have to be careful, though, if the file is large, as is mentioned in that issue.

tone
  • 1,374
  • 20
  • 47
0

What worked for me was to add responseType: 'blob' to the options on the http request, and then just use the result as a blob, rather than trying to construct a blob.

So, e.g.:

downloadFile() {
  this.gdwService.getGdwFile(1).subscribe(fileBlob => {
    saveAs(fileBlob, "Salesbypostcode.docx");
  });
}

getGdwFile(gdwQueryJobId: number) {
  return this.http.get(`/api/Gdw/getGdwPdfFile?gdwQueryJobId=${gdwQueryJobId}`,
      {
        headers: new HttpHeaders({
           "Content-Type": "application/json"             
      }),
      responseType: 'blob'
  });
}
GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
  • That didn't work - the file was still corrupt. I also tried returning a new FileContentResult and that didn't work. – tone Apr 24 '18 at 02:11