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
- Manipulation des erreurs inconnues dans le rapporteur
- Puis-je utiliser les directives AngularJs pour appliquer un style à un élément pseudo
- Comment puis-je forcer jQuery à "écouter" et à activer les plugins sur les éléments ultérieurs de l'AngularJS ng-repeat?
- Test ne fonctionne pas sur karma / jasmine / require.js 'Il n'y a pas d'horodatage pour * lib *!' Erreur
- AVERTISSEMENT: Essayé de charger angulairement plus d'une fois … en raison de jQuery … pourquoi?
{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 '
Pourquoi le content
reçu dans les angularjs contenait-il déjà des caractères au lieu d'un octet de tableau?
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?
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.