Génère csv à partir de mvc web api httpresponse et recevez-le par angularjs pour téléchargement

J'essaie de générer un fichier CSV à partir de mon Web api et de recevoir ce fichier via angularjs. J'ai un contrôleur API comme ci-dessous:

[HttpPost] public HttpResponseMessage GenerateCSV(FieldParameters fieldParams) { var output = new byte[] { }; if (fieldParams!= null) { using (var stream = new MemoryStream()) { this.Serialize(fieldParams, stream); stream.Flush(); output = stream.ToArray(); } } var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) }; result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "Fields.csv" }; return result; } 

Dans mes angles, j'ai ceci:

 $scope.save = function () { var csvInput= extractDetails(); // File is an angular resource. We call its save method here which // accesses the api above which should return the content of csv File.save(csvInput, function (content) { console.log(content); // only creates a csv file with "[object Object]" written in it var hiddenElement = document.createElement('a'); hiddenElement.href = 'data:text/csv;charset=utf-8,\uFEFF' + encodeURI(content.Parameters); hiddenElement.target = '_blank'; hiddenElement.download = 'myFile.csv'; hiddenElement.click(); }); }; 

Disons par exemple, dans mon contrôleur API, le contenu de la réponse est

sortie

{Byte [152]}

[0]: 83

[1]: 101

[2]: 44

[3]: 67

[4]: 10

Lorsque je reçois ceci dans angularjs et je mets la valeur du content dans le journal de la console (chrome), c'est ce que je reçois:

{Paramètres: Array [1], $ promesse: Object, $ resolved: true, $ get: function, $ save: function …}

0: "S"

1: "e"

2: ","

3: "C"

4: "↵"

$ Promesse: objet

$ Résolu: vrai '

  1. Pourquoi le content reçu dans les angularjs contenait-il déjà des caractères au lieu d'un octet de tableau?

  2. Comment puis-je contrôler le content de telle sorte que je n'utiliserai que les données liées à csv et supprimez $promise et $resolved ? Pourquoi sont-ils inclus en premier lieu? Comment les supprimer?

  3. Quelle est la manière appropriée de générer un csv si ce que je fais est faux? : |

J'ai oublié de mettre à jour, mais j'ai maintenant trouvé un moyen de résoudre ceci:

Il y aura deux API, un (POST) se souviendra des données à utiliser dans le traitement et une autre (GET) qui distribuera le fichier.

POSTER:

  [HttpPost] public async Task<HttpResponseMessage> BuildFile(FileParameters fileParams) { var guid = Guid.NewGuid().ToString(); if (fileParams!= null) { await Task.Run(() => FileContents.Add(guid, fileParams)); return this.Request.CreateResponse(HttpStatusCode.OK, new { Value = guid }); } return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid data"); } 

Dans les Angulaires, rappelez-vous le guid retourné et passez-le à un autre api:

  location.href = '/api/file/generatefile' + '?guid=' + generatedGuidFromAPI + '&reportName=' + $scope.reportName; 

Et voici le contrôleur API generatefile dans MVC:

OBTENIR:

  [HttpGet] public async Task<HttpResponseMessage> GenerateFile(string guid, string reportName) { byte[] output = null; if (FileContents.ContainsKey(guid)) { await Task.Run(() => { using (var stream = new MemoryStream()) { this.CreateFile(FileContents[guid], stream); stream.Flush(); output = stream.ToArray(); } }); } FileContents.Remove(guid); if (output != null) { var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) }; result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = reportName + ".csv" }; return result; } return this.Request.CreateErrorResponse(HttpStatusCode.NoContent, "No record found"); } 

L'utilisation de l' location.href amènera le navigateur à télécharger automatiquement le fichier, vous demandant de le sauvegarder ou non.

Voici comment je le fais: (testé en chrome)

  // WebAPI controller action public IHttpActionResult Get(string rpt, DateTime date) { List<DailyMIReportViewModel> list = new List<DailyMIReportViewModel>(); // Do some stuff to generate list of items // Download Requested if (rpt == "dailymidl") { // Create byte array of csv byte[] csvData = WriteCsvWithHeaderToMemory(list); // create FileContentResult of cdv byte array FileContentResult result = new FileContentResult(csvData, "application/octet-stream"); // set filename in FileContentResult result.FileDownloadName = "Report.csv"; return Ok(result); } // Data Requested return Ok(list); // Client-side angularjs // Called on button click $scope.generateMIDownload = function (forDate) { // Using $resource to return promise with FileContentResult payload reportsRepository.dailymidl(forDate).$promise.then( function (data) { //ok // NOTE: the base64 part is what got it working var dataUrl = 'data:application/octet-stream;base64,' + data.FileContents var link = document.createElement('a'); angular.element(link) .attr('href', dataUrl) .attr('download', data.FileDownloadName) .attr('target','_blank') link.click(); }, function (response) { //not ok }); } // Reports Repository (for ref) angular.module('msgnr').factory('reportsRepository', function ($resource) { return { dailymidl: function (date) { return $resource('/api/Report/', { rpt: 'dailymidl', date: date, toDate: date }).get(); } } }); 

Incase, ça aide quelqu'un d'autre.