Angular 10 + Web API C# : upload file / download file

Dès qu’il s’agit d’utiliser Angular et une Web API C# pour faire de l’upload ou du téléchargement de fichier, c’est la galère !

Je vous propose donc les solutions que j’ai mis en place et qui fonctionne avec Angular 10 et la Web API 5.2.7 ou .NET 5.

Mise à jour du 01/12/2020

  • Ajout d’un exemple avec le .NET 5
  • Remplacement du package de téléchargement par ma version personnelle compatible Angular

1. Upload file

Comment envoyer un fichier depuis l’angular vers la Web API C# ?

Il y a énormément de tutoriels sur internet, mais quasiment aucun n’a fonctionné correctement. Voici la solution que j’utilise.

Partie Web API

ASP.NET 4.8

Ce code est assez simple, le « HttpContext.CurrentRequest.Files » nous donne lia liste des fichiers de la requête. Il suffit de faire un « SaveAs(…) » pour enregistrer le fichier.

using System.Web;
using System.Web.Http;
namespace Test {
    public class TestController : ApiController {
        public IHttpActionResult Post()
        {
            var httpRequest = HttpContext.Current.Request;
            if (httpRequest.Files.Count == 1)
            {
                HttpPostedFile file = httpRequest.Files[0];
                file.SaveAs("...");
            }
            return Ok();
        }
    }
}

ASP.NET Core (.NET 5)

using System.Web;
using System.Web.Http;
namespace Test {
    public class TestController : ApiController {
public IHttpActionResult Post() { var files = Request.Form.Files;
if (files.Count == 1) {
using (var stream = System.IO.File.Create("..")) {
files[0].CopyTo(stream);
}
} return Ok(); }
} }

Ca fonctionne très bien si vous avez mis les droits d’accès en modification à l’utilisateur « IIS_IUSRS » de IIS sur le dossier d’écriture.

Partie Angular

Cette partie est plus complexe car elle dépend de la version d’Angular. Ici, nous sommes en Angular 10. Le code pour envoyer un fichier est le suivant.

Service

Il faut bien noter que l’appel classique « HttpClient.Post » ne fonctionne pas pour l’envoi d’un fichier vers la Web API C#. Il faut écrire une requête avec un corps (body) personnalisé.

export class ImportService {
   constructor(privatehttp: HttpClient) { }

   public post(file:File): Observable<any> {
      const formData = new FormData();
      formData.append('file', file, file.name);
      return this.http.request('POST', this.ApiUrl, { body:formData });
   }
}

Composant

L’autre point important concerne le composant. Il ne faut pas mettre de « [(ngModel)] » sur le « input file » sinon la propriété sera liée au chemin du fichier et non pas au fichier lui-même.

Il est nécessaire d’utiliser l’événement « change » de l’input pour récupérer le fichier.

Côté HTML :

<input type="file" id="file" name="file" (change)="fileSelected($event)">

Côté TypeScript :

public importFile: File;

public fileSelected(model:Event) {
   const files = (model.target as HTMLInputElement).files;
   if (files.length > 0) {
      this.importFile = files[0];
   }
}

 

2. Download file

Maintenant que nous avons envoyé notre fichier vers le serveur, il est intéressant de pouvoir faire l’inverse : télécharger le fichier vers l’Angular et l’utilisateur.

Comme pour l’envoi, il existe des dizaines de solutions mais peu ont fonctionnées … je vous propose donc la mienne pour un fichier EXCEL.

Partie Web API

Ce code permet d’envoyer un fichier EXCEL à partir de son chemin sur le disque dur. A noter qu’il est possible d’envoyer directement un fichier généré en mémoire la réponse utilise un stream.

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Hosting;
using System.Web.Http;
namespace Test {
   public class ExportController : ApiController {
      public HttpResponseMessage Get()
      {
         var fileName = "C:\monfichier.xlsx";
         var contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

         var result = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
         var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
         result.Content = new StreamContent(stream);
         result.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
         return result;
      }
   }
}

Ici, il s’agit bien d’envoyer un fichier EXCEL car le « Content-Type » à la valeur qu’il faut. Selon le type de fichier, il faut mettre une valeur différente :

  • EXCEL : application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • CSV : text/csv

Pour ceux qui ne savent pas vraiment quoi mettre, il faut se référer à la liste officielle.

Partie Angular

Le code natif d’Angular ne permet pas simplement d’envoyer le fichier récupéré de la Web API C# vers l’utilisateur. J’utilise le package NPM « @clemox/file-saver » pour simplifier les choses.

De plus, comme pour l’upload, il n’est pas possible d’utiliser la méthod « HttpClient.Get(…) », il faut déclarer sa propre méthode pour récupérer le corps de la réponse. Cela donne le service Angular :

import { Injectable } from '@angular/core';
import { NgxFileSaverService } from '@clemox/ngx-file-saver';

@Injectable() export class ExportService { constructor(private fileSaver: NgxFileSaverService) { } public get() {
this.fileSaver.saveUrl('http//...', 'mon_fichier.csv');
} }

Et voilà, en appelant la méthode « get », vous téléchargerez le fichier 🙂