If we have an Angular client app that needs to download a file (for example a PDF file) from an Asp Net Core 2 api Controller , we can follow what is described in this post.

The first implementation is on the server side (an Asp Net Core 2 Controller).

So, for example into our controller UserController, we can write the download method (HTTPGET) using MemoryStream and FileStream to download file from the server (that we suppose is into the “App_Data” folder) like in the following code:

// using statements and namespace declaration omitted
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] public class UserController : Controller
{ [HttpGet({filename})] public async Task<IActionResult> DownloadFile(string filename) { try { string file = Path.Combine( Path.Combine(AssemblyDirectory, "App_Data"), filename); var memory = new MemoryStream(); using (var stream = new FileStream(file, FileMode.Open)) { await stream.CopyToAsync(memory); } memory.Position = 0; return File(memory, GetMimeType(file), filename); } catch (Exception e) { return BadRequest(e); } } private static string AssemblyDirectory { get { string codeBase = Assembly.GetExecutingAssembly().CodeBase; UriBuilder uri = new UriBuilder(codeBase); string path = Uri.UnescapeDataString(uri.Path); return Path.GetDirectoryName(path); } } private string GetMimeType(string file) { string extension = Path.GetExtension(file).ToLowerInvariant(); switch (extension) { case ".txt": return "text/plain"; case ".pdf": return "application/pdf"; case ".doc": return "application/vnd.ms-word"; case ".docx": return "application/vnd.ms-word"; case ".xls": return "application/vnd.ms-excel"; case ".png": return "image/png"; case ".jpg": return "image/jpeg"; case ".jpeg": return "image/jpeg"; case ".gif": return "image/gif"; case ".csv": return "text/csv"; default: return ""; } }
}

Now, on the client side, we can write our Angular service tha provide to the component the method to download the file:

download-service.ts

import { Injectable, Injector } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { URLSearchParams, ResponseContentType } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/catch'; @Injectable()
export class DownloadService { public getFile(filename: string) { return this.getFileEndpoint(filename).toPromise(); } public getFileEndpoint(filename: string): Observable<Response> { return this.http.get( this.baseurl + '/api/user/' + filename, this.getAuthHeader(false, true)) .map((response: Response) => { return response; }) .catch(error => { return throw error; }); } private getAuthHeader(includeJsonContentType?: boolean, includeBlobResponseContentType?: boolean): RequestOptions { let headers = new Headers({ 'Authorization': 'Bearer ' + this.authService.accessToken }); if (includeJsonContentType) headers.append("Content-Type", "application/json"); headers.append("Accept", `application/vnd.iman.v${EndpointFactory.apiVersion}+json, application/json, text/plain, */*`); headers.append("App-Version", ConfigurationService.appVersion); if (includeBlobResponseContentType) return new RequestOptions({ responseType: ResponseContentType.Blob, headers: headers }); else return new RequestOptions({ headers: headers }); } private baseUrl() { if (window.location.origin) return window.location.origin; return window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : ''); }
}

Now that our service is ready, we can call it from our componet to download the file:

file-component.ts

import { DownloadService } from './download-service.ts';
// other imports statements omitted export class FileComponet
{ constructor(private downloadService: DownloadService) {} showPdfDocument() { let filename: string = 'document.pdf'; this.downloadService.getFile(filename).then((result: any) => { this.showFile(result._body, filename); }); } private showFile(blob: any, filename: string) { // It is necessary to create a new blob object with mime-type // explicitly set otherwise only Chrome works like it should let newBlob = new Blob([blob], { type: "application/pdf" }); // IE doesn't allow using a blob object directly as link href // instead it is necessary to use msSaveOrOpenBlob if (window.navigator && window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveOrOpenBlob(newBlob); return; } // For other browsers: // Create a link pointing to the ObjectURL containing the blob. let data = window.URL.createObjectURL(newBlob); let link = document.createElement('a'); link.href = data; link.download = filename; link.click(); setTimeout(() => { // For Firefox it is necessary to delay revoking the ObjectURL window.URL.revokeObjectURL(data); }, 100); }
}

Laisser un commentaire