Mr. Jay
Mr. Jay

Reputation: 153

angular 6 download excel from API

I am trying to download an excel file from server. UI is in angular 6 and service is C# Web API. Firstly, I am not getting whether this download method need to be HTTPGET or HTTPPOST. Using some help from other forum, I have written code below. I don't see any error nor I see that debugger stop inside subscribe method. when I click on file link to download from angular app the page redirect to localhost: port (start page)

     [HttpGet]//http get as it return file 
        public HttpResponseMessage DownloadAttachment(string fileName)
        {
            //below code locate physical file on server 
            var localFilePath = HttpContext.Current.Server.MapPath("../../uploadFiles/" + fileName);
            HttpResponseMessage response = null;
            if (!File.Exists(localFilePath))
            {
                //if file not found than return response as resource not present 
                response = Request.CreateResponse(HttpStatusCode.Gone);
            }
            else
            {
                //if file present than read file 
                var fStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read);

               //compose response and include file as content in it
                response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    // Content = new StreamContent(fStream)
                    Content = new StreamContent(fStream)
                };

                //set content header of reponse as file attached in reponse
                response.Content.Headers.ContentDisposition =
                new ContentDispositionHeaderValue("attachment")
                {
                    FileName = Path.GetFileName(fStream.Name)
                };
                //set the content header content type as application/octet-stream as it      
                //returning file as reponse 
               response.Content.Headers.ContentType = new
                             MediaTypeHeaderValue("application/octet-stream");


                response.Content.Headers.ContentLength = fStream.Length;
                response.Headers.Add("fileName", fileName);
            }
            return response;
        }

Now, from Angular calling:

   downloadFile(fileName: string) {
  this.Service.postAndGetResponse(fileName).subscribe(fileData => {
   // const b: any = new Blob([fileData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    // .map(res => new Blob([res.blob()],{ type: 'application/vnd.ms-excel' }));
   // const  url = window.URL.createObjectURL(b);
   //   window.open(url);
   console.log (fileData);
    }
  );
}

in Service.ts

     postAndGetResponse(fileName) {
    return this.http.get(this.baseURL + 'DataEvent/DownloadEventAttachment?fileName=' + fileName, {responseType: 'blob' as 'blob'}).pipe(
      map((x) => {
        return x;
    })
    );
  }

I have put debugger in downloadFile method inside subscribe, but it never stops there as if nothing is returned or call is lost.

When I use postman to call WEB API method, the response is returned. I don't see any text format- it seems to be corrupted/binary?? the format is like below in response body:

    ��ࡱ�>��   �����������������

Upvotes: 1

Views: 13180

Answers (2)

Hien Nguyen
Hien Nguyen

Reputation: 18975

I tried to reproduce your code. Following code is working. Change the code in postAndGetResponse only to return http get call.

You can use a link or FileSaver to save blob content.

postAndGetResponse(fileName) {
    return this.http.get('http://localhost:62292' + '/api/TestExport/DownloadAttachment?fileName=' + fileName, { responseType: 'blob' as 'blob' });
  }

Update download file method

downloadFile(fileName: string) {
    this.settingService.postAndGetResponse(fileName).subscribe(fileData => {

      const blob: any = new Blob([fileData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });

      let link = document.createElement("a");

      if (link.download !== undefined) {
        let url = URL.createObjectURL(blob);
        link.setAttribute("href", url);
        link.setAttribute("download", fileName);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      }
    }
    );
  }

And API code, change verb to [AcceptVerbs("GET")]

public class TestExportController : ApiController
    {

        [Route("api/TestExport/DownloadAttachment")]
        [AcceptVerbs("GET")]
        public HttpResponseMessage DownloadAttachment(string fileName)
        {
            //below code locate physical file on server 
            var localFilePath = HttpContext.Current.Server.MapPath("../../uploadFiles/" + fileName);
            HttpResponseMessage response = null;
            if (!File.Exists(localFilePath))
            {
                //if file not found than return response as resource not present 
                response = Request.CreateResponse(HttpStatusCode.Gone);
            }
            else
            {
                //if file present than read file 
                var fStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read);

                //compose response and include file as content in it
                response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    // Content = new StreamContent(fStream)
                    Content = new StreamContent(fStream)
                };

                //set content header of reponse as file attached in reponse
                response.Content.Headers.ContentDisposition =
                new ContentDispositionHeaderValue("attachment")
                {
                    FileName = Path.GetFileName(fStream.Name)
                };
                //set the content header content type as application/octet-stream as it      
                //returning file as reponse 
                response.Content.Headers.ContentType = new
                              MediaTypeHeaderValue("application/octet-stream");


                response.Content.Headers.ContentLength = fStream.Length;
                response.Headers.Add("fileName", fileName);
            }
            return response;
        }
    }

Upvotes: 2

Mr. Jay
Mr. Jay

Reputation: 153

I figured out that posting for someone need help with same problem:

    downloadFile(fileName: string) {
   const isIE = /*@cc_on!@*/false || !!document['documentMode'];
   const isChrome = !!window['chrome'];
    this.service.postAndGetResponse(fileName).subscribe(fileData => {
    const blob: any = new Blob([fileData], { type: 'application/vnd.openxmlformats- 
      officedocument.spreadsheetml.sheet' });
    if (isIE) { // this code doesn't work for chrome
      console.log('Manage IE download>10');
      window.navigator.msSaveOrOpenBlob(blob, fileName);
  } else if (isChrome) {  // this below code doesn't work for IE
    const link = document.createElement('a');
    if (link.download !== undefined) {
     const url = URL.createObjectURL(blob);
     link.setAttribute('href', url);
     link.setAttribute('download', fileName);
     link.setAttribute('target', '_self');
     document.body.appendChild(link);
     link.click();
     document.body.removeChild(link);
    }
  } else {
    window.navigator.msSaveOrOpenBlob(blob, fileName);
  }
});
}

Upvotes: 1

Related Questions