I recently ran into a situation where I had to provide an export option for a web app screen. The requirements were that the export needed to be in a csv format, a web api needed to provide the csv results and the web app needed to save the csv results to a file with minimal user intervention.

I will discuss the various options I found while researching and ultimately what I went with.

Returning csv from a web api method

There are a couple of options to choose from such as converting the results to csv and returning the csv string from the method or creating a custom MediaTypeFormatter. I chose to go with the later and followed this Asp.Net tutorial.

Note: Keep in mind the formatter is global, so any methods that return the type you allow to be converted can also return csv when the Accept: text/csv header is used.

Making the call using Angularjs

This is really just like any other call to the web api, accept you need to add the Accept: text/csv to the header.

// Using the get shortcut method
$http.get("url to web api method", {
    headers: {
        "Accept": "text/csv"

Thats it, now your custom MediaTypeFormatter will see the Accept: text/csv and convert the results to csv before returning them to the client.

Saving the results

There seems to be some spec in the FileSystem Api for writing files, but it doesn’t appear any browser supports it right now, but Chrome and Opera (see CanIUse). So I will be using the FileSaver.js created by Eli Grey.

So we will call the web api and in the promise, create a blob to store the results and pass it off to FileSaver.js which will handle the saving.

// $http.get up here
.then(function(response) {
    var fileContents = new Blob([response.data], { type: "text/csv" });

    saveAs(fileContents, "export.csv");

Simple as that, thanks to Eli Grey I don’t have to fiddle around with trying to figure out how to save files in the various browsers.

Update 7/22/2015

I changed my approach slightly to use the MediaTypeFormatter in a non-global way. In this project I preferred to set the formatter when I create the response.

return this.Request.CreateResponse(HttpStatusCode.OK, results,
  new CsvFormatter());

This way it is specific to the csv call and no extra code it written.

I also decided to not use a generic formatter class and instead create a base csv formatter with inheriting specific csv formatters (one for each controller/response object). Although a little more code, this is much easier to read, understand and maintain. For now I have also decided to keep the csv string creation for each object in a separate extension method (although now it may make more sense to move that into the specific inheriting formatters).