Reputation: 1845
I have an Angular application with an ASP.NET Web API.
I want to download a file stored on my server. Currently, this is the code I have:
[HttpGet]
[Route("downloadFile")]
[JwtAuthentication] //Only a connected user can download the file
public async Task<HttpResponseMessage> DownloadFile(string path)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var fileStream = File.OpenRead(path);
result.Content = new StreamContent(fileStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = fileStream.Length;
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileStream.Name,
Size = fileStream.Length
};
return result;
}
And in my Angular code:
// file-navigation.service.ts
downloadFile(file: FileElement) {
const data = { path: this.formatPath(true) + file.name };
return this.http.get(this.apiUrl + '/downloadFile', { params: data, responseType: 'blob' });
}
// file-navigation.component.ts
this.fileNavigationService.downloadFile(element).subscribe(result => {
this.generateDownload(element, result, false);
});
generateDownload(element: FileElement, blob: Blob, isArchive: boolean) {
const fileName = element != null ? element.name : 'Archive';
if (navigator.appVersion.toString().indexOf('.NET') > 0) {
window.navigator.msSaveBlob(blob, fileName + (isArchive ? '.zip' : ''));
} else {
const link = document.createElementNS(
'http://www.w3.org/1999/xhtml',
'a'
);
(link as any).href = URL.createObjectURL(blob);
(link as any).download = fileName + (isArchive ? '.zip' : '');
document.body.appendChild(link);
link.click();
setTimeout(function () {
document.body.removeChild(link);
link.remove();
}, 100);
}
}
With this, I successfully download a file from the server.
However, the download bar in Chrome only appears when the download is done. So if the file is too big, the user won't get any indicator that his file is currently being downloaded.
Below is a screenshot of a 16Mb file being downloaded. The server is currently sending data but the download bar doesn't appear.
Then, once the download has completed, the file appears in the download bar at the bottom of the screen.
How can I send the file to the browser so that it shows this indicator to the user?
Thank you very much.
EDIT:
As @CodeCaster pointed out, redirecting to the URL could work, however, my URL is protected so that only connected users can download the file.
Upvotes: 5
Views: 7767
Reputation: 31
On Angular side, just use anchor tag and pass the API URL in href
attribute.
<a href = {this.apiUrl + '/downloadFile' + '?' + 'your params'}>Download</a>
and also on server side before streaming data, make sure you have set the following response header.
res.setHeader('content-length',data.ContentLength) (optional)
res.setHeader('content-type', mimetype);
res.setHeader('content-disposition', 'attachment; filename');
Upvotes: 2