Generate csv from mvc web api httpresponse and get it using angularjs to download

I am trying to create a CSV file from my web api and get this file through angularjs. I have an API controller as shown below:

[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; } 

In my angularjs, I have this:

 $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(); }); }; 

Let's say, for example, in my controller API, the content of the response

Exit

{byte [152]}

[0]: 83

[1]: 101

[2]: 44

[3]: 67

[4]: 10

When I get this in angularjs and I put the content value in the console log (chrome), this is what I get:

{Parameters: Array [1], $ prom: Object, $ resolved: true, $ get: function, $ save: function ...}

0: "S"

1: "e"

2: ","

3: "C"

4: "↵"

$ promise: object

$ allowed: true`

  • Why is the content obtained in angularjs already containing characters instead of an array byte?

  • How can I manage the content in such a way that I will use the associated csv data and delete $promise and $resolved ? Why are they included in the first place? How to remove them?

  • What is the correct way to generate csv if what i am doing is wrong ?: |

+4
javascript angularjs asp.net-web-api csv
Nov 30 '13 at 18:27
source share
2 answers

Forgot to update this, but now I have found a way to solve this problem:

There will be two APIs, one (POST) will remember the data that will be used in processing, and another (GET) that will distribute the file.

POST:

  [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"); } 

In AngularJs, remember the returned guid and pass this to another api:

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

And here is the generatefile API controller in MVC:

Get

  [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"); } 

using location.href will cause the browser to automatically download the file, asking him to save it or not.

+5
Jan 04 '14 at 6:09
source

Here's how I do it: (tested in 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(); } } }); 

If it helps someone else.

0
Mar 19 '14 at 21:14
source



All Articles