Download any file from the server using Angular 8+ and ASP.NET CORE 2+ version.
Controller implementation to download the file:
[HttpGet]
[Route("download")]
public async Task Download([FromQuery] string file) {
var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
var filePath = Path.Combine(uploads, file);
if (!System.IO.File.Exists(filePath))
return NotFound();
var memory = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, GetContentType(filePath), file);
}
Create angular service
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest, HttpEvent, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class DownloadService {
private baseApiUrl: string;
private apiDownloadUrl: string;
private apiUploadUrl: string;
private apiFileUrl: string;
constructor(private httpClient: HttpClient) {
this.baseApiUrl = 'http://localhost:5001/api/';
this.apiDownloadUrl = this.baseApiUrl + 'download';
this.apiUploadUrl = this.baseApiUrl + 'upload';
this.apiFileUrl = this.baseApiUrl + 'files';
}
public downloadFile(file: string): Observable> {
return this.httpClient.request(new HttpRequest(
'GET',
`${this.apiDownloadUrl}?file=${file}`,
null,
{
reportProgress: true,
responseType: 'blob'
}));
}
}
Create a model in angular
export interface ProgressStatus {
status: ProgressStatusEnum;
percentage?: number;
}
export enum ProgressStatusEnum {
START, COMPLETE, IN_PROGRESS, ERROR
}
Create a component to download a file
<button
[disabled]="disabled"
class="button download"
[ngClass]="{'disabled': disabled}"
(click)="download()">download
Create a child component to download a file. Following code in typescript file:
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { HttpEventType } from '@angular/common/http';
import { UploadDownloadService } from 'src/app/services/upload-download.service';
import { ProgressStatus, ProgressStatusEnum } from 'src/app/models/progress-status.model';
@Component({
selector: 'app-download',
templateUrl: 'download.component.html'
})
export class DownloadComponent {
@Input() public disabled: boolean;
@Input() public fileName: string;
@Output() public downloadStatus: EventEmitter;
constructor(private service: UploadDownloadService) {
this.downloadStatus = new EventEmitter();
}
public download() {
this.downloadStatus.emit( {status: ProgressStatusEnum.START});
this.service.downloadFile(this.fileName).subscribe(
data => {
switch (data.type) {
case HttpEventType.DownloadProgress:
this.downloadStatus.emit( {status: ProgressStatusEnum.IN_PROGRESS, percentage: Math.round((data.loaded / data.total) * 100)});
break;
case HttpEventType.Response:
this.downloadStatus.emit( {status: ProgressStatusEnum.COMPLETE});
const downloadedFile = new Blob([data.body], { type: data.body.type });
const a = document.createElement('a');
a.setAttribute('style', 'display:none;');
document.body.appendChild(a);
a.download = this.fileName;
a.href = URL.createObjectURL(downloadedFile);
a.target = '_blank';
a.click();
document.body.removeChild(a);
break;
}
},
error => {
this.downloadStatus.emit( {status: ProgressStatusEnum.ERROR});
}
);
}
}
Add the following implementation in parent component:
<app-download [disabled]="showProgress" [fileName]="file" (downloadStatus)="downloadStatus($event)">
<p *ngIf="showProgress"> progress {{percentage}}%
Add the following implementation in parent typescript component:
import { Component, OnInit } from '@angular/core';
import { UploadDownloadService } from 'src/app/services/upload-download.service';
import { ProgressStatusEnum, ProgressStatus } from 'src/app/models/progress-status.model';
@Component({
selector: 'app-filemanager',
templateUrl: './file-manager.component.html'
})
export class FileManagerComponent implements OnInit {
public files: string[];
public fileInDownload: string;
public percentage: number;
public showProgress: boolean;
public showDownloadError: boolean;
public showUploadError: boolean;
constructor(private service: UploadDownloadService) { }
ngOnInit() {
this.getFiles();
}
private getFiles() {
this.service.getFiles().subscribe(
data => {
this.files = data;
}
);
}
public downloadStatus(event: ProgressStatus) {
switch (event.status) {
case ProgressStatusEnum.START:
this.showDownloadError = false;
break;
case ProgressStatusEnum.IN_PROGRESS:
this.showProgress = true;
this.percentage = event.percentage;
break;
case ProgressStatusEnum.COMPLETE:
this.showProgress = false;
break;
case ProgressStatusEnum.ERROR:
this.showProgress = false;
this.showDownloadError = true;
break;
}
}
}
DONE!