I have a file on the server that I want to send to the client:
[HttpPost]
public IActionResult Test()
{
byte[] bytes = System.IO.File.ReadAllBytes(Path.C
To download any file, first install the following,
npm install rxjs --save
npm install file-saver --save
Include these packages in your component(Angular 2+),
import { Observable } from 'rxjs';
import { saveAs } from 'file-saver';
import { map } from "rxjs/operators";
import { Subject } from 'rxjs';
import { HttpEventType, HttpClient } from '@angular/common/http';
Front-end code,
<input type="button" placeholder="Download" value="Download" (click)="download(file)" />
Angular Code,
download(file) {
let fileName = file;
let checkFileType = fileName.split('.').pop();
var fileType;
if (checkFileType == ".txt") {
fileType = "text/plain";
}
if (checkFileType == ".pdf") {
fileType = "application/pdf";
}
if (checkFileType == ".doc") {
fileType = "application/vnd.ms-word";
}
if (checkFileType == ".docx") {
fileType = "application/vnd.ms-word";
}
if (checkFileType == ".xls") {
fileType = "application/vnd.ms-excel";
}
if (checkFileType == ".png") {
fileType = "image/png";
}
if (checkFileType == ".jpg") {
fileType = "image/jpeg";
}
if (checkFileType == ".jpeg") {
fileType = "image/jpeg";
}
if (checkFileType == ".gif") {
fileType = "image/gif";
}
if (checkFileType == ".csv") {
fileType = "text/csv";
}
this.DownloadFile(fileName, fileType)
.subscribe(
success => {
saveAs(success, fileName);
},
err => {
alert("Server error while downloading file.");
}
);
}
DownloadFile(filePath: string, fileType: string): Observable<any> {
let fileExtension = fileType;
let input = filePath;
return this.http.get(this.yourApiUrl + "?fileName=" + input, {
responseType: 'blob',
observe: 'response'
})
.pipe(
map((res: any) => {
return new Blob([res.body], { type: fileExtension });
})
);
}
.NET Core API code,
[HttpGet]
public async Task<FileStream> DownloadFile(string fileName)
{
return new FileStream(file, FileMode.Open, FileAccess.Read);
}
You can use a file result and just provide an api link that will return a FileContentResult.
public IActionResult Download(// some parameter)
{
// get the file and convert it into a bytearray
var locatedFile = ....
return new FileContentResult(locatedFile, new
MediaTypeHeaderValue("application/octet"))
{
FileDownloadName = "SomeFileDownloadName.someExtensions"
};
}
Now you only need to provide the link and browser will know how to handle it. No need to do it yourself then.
Edit: I just tested this approach with angular, you need to do the following to download the file when using angulars HttpClient.
First you need to install file-saver via npm.
npm i --save file-saver
Then in your module import and include HttpClientModule
import { HttpClientModule } from '@angular/common/http';
...
@NgModule({
imports: [
HttpClientModule
...
]
...
})
Now go ahead to your service and do the following
import { HttpClient } from '@angular/common/http';
import { saveAs } from 'file-saver';
@Injectable()
export class MyFileService {
public constructor(private http: HttpClient) {}
public downloadFile() {
this.http.get('my-api-url', { responseType: 'blob' }).subscribe(blob => {
saveAs(blob, 'SomeFileDownloadName.someExtensions', {
type: 'text/plain;charset=windows-1252' // --> or whatever you need here
});
});
}
Then blob is handled and a file-save dialog is created.
I do not know why the option specified in the question does not work. But I found a solution, so to say "in another forest". I'm not very versed, so I'll just describe the process of solving the problem. For the beginning I will immediately say that the problem was on the client's side. The method on the server worked correctly from the start. I decided to use another method to download the files "fetch". And came across the next post in the forum. From there I took the following answer
this.httpClient
.fetch(url, {method, body, headers})
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(url => {
window.open(url, '_blank');
URL.revokeObjectURL(url);
});
He did not work for me either. I changed it so
fetch(url, {
method: 'POST',
headers: this.headers()
})
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(url => {
window.open(url, '_blank');
});
Because of this line nothing happened
URL.revokeObjectURL(url);
This option worked, but with screwed. He saved the file with a strange name and no extension. Then I changed it so.
fetch(url, {
method: 'POST',
headers: this.headers()
})
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(url => {
var link = document.createElement("a");
link.setAttribute("href", url);
link.setAttribute("download", "test.docx");
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
And it works! I apologize for the English. I'm using Google translator