9

I'm generating an Excel file in my WebAPI. I "store" it in a memorystream and then put in the the response as follow :

var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(ms) };

            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = projectName + ".xlsx"
            };
           // ms.Close();
            return result;

It looks like the server side is working correcty. If I'm writing that memorystream into a filestream, the file is created and can be open without any problem.

On angular side, how can I recreate the file when click on a button?

I tried something like this :

$scope.exportQuotas = function (projectName) {
    homeService.GetQuotas(projectName, $routeParams.token, $scope.selection).then(
             function (data) {
                 var dataUrl = 'data:application/octet-stream;' + data
                 var link = document.createElement('a');
                 angular.element(link)
                   .attr('href', dataUrl)
                   .attr('download', "bl.xlsx")
                   .attr('target', '_blank')
                 link.click();
             })
}

The file is created but when I tried to open it, it's corrupted... I've tried changing the data type to vnd.ms-excel in angular but it didn't work... How can I get the file to be downloaded on click?

EDIT After Jorg answer, I tried the following : What the api returns is :

Status Code: 200
Pragma: no-cache
Date: Tue, 02 Sep 2014 02:00:24 GMT
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Content-Type: application/binary
Access-Control-Allow-Origin: *
Cache-Control: no-cache
X-SourceFiles: =?UTF-8?B?        QzpcVXNlcnNcdHJpaGFuaC5waGFtXFByb2plY3RzXFF1b3RhUXVlcnlcUXVvdGFRdWVyeUFQSVxhcGlccXVvdGFcR2V0?=
Content-Disposition: attachment; filename=O14Y0129AUG.xlsx
Content-Length: 13347
Expires: -1

From what I can see, it looks correct.

In client side :

                 var file = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;' });
                 var fileURL = URL.createObjectURL(file);
                 window.open(fileURL);

A excel file is created but it's still corrupted...

Thanks

tri
  • 191
  • 1
  • 3
  • 9
  • I got mine working like this: http://stackoverflow.com/questions/22447952/angularjs-http-post-convert-binary-to-excel-file-and-download/22448640#22448640 – Jorg Sep 02 '14 at 00:20
  • It didn't work for me though :( file is corrupted... also as metionned, the filename is weird... – tri Sep 02 '14 at 02:20

2 Answers2

17

I had the same problem. The file was OK server side, but when downloaded it became corrupt.

What solved it for me was to add responseType: "arraybuffer" to the server request.

Then when calling this line var file = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;' }); The data variable should be of type ArrayBuffer, and not a string.

daniel
  • 334
  • 3
  • 6
1

The main issue comes from the fact that by default, XMLHttpRequest uses the default response type which is an empty String. See this link. Your binary data are therefore not correctly handled.

When using javascript API, you need to take care of the response type for binary data. Otherwise, it will be interpreted as a String.

API like angular-file-upload (last version is currently 1.1.5) for example does not provide the possibility to set the response type of data received after an upload. I had to update the API to define the response type.

J.M. Kenny
  • 384
  • 4
  • 11