The CsvMediaTypeFormatter
on Github makes it possible to support text/csv
media type to the Web API stack. However, I wanted to rewrite it using the ToCsv() extension method from my earlier post.
using App.Helpers;
namespace App.Web.MediaTypes
{
public class CsvMediaTypeFormatter : BufferedMediaTypeFormatter
{
public CsvMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}
public override bool CanReadType(Type type)
{
return false;
}
public override bool CanWriteType(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
// type must implement IEnumerable
return typeof(IEnumerable).IsAssignableFrom(type);
}
public override void WriteToStream(
Type type,
object value,
Stream writeStream,
HttpContent content)
{
using (var writer = new StreamWriter(writeStream))
{
string csv = ((IEnumerable)value).ToCsv();
writer.Write(csv);
}
}
}
}
Add the CsvMediaTypeFormatter
to the formatters collection in the start up configuration code.
using App.Web.MediaTypes;
namespace App.Web
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// add the media formatter to the pipeline
config.Formatters.Add(new CsvMediaTypeFormatter());
}
}
}
With the above configuration in place, a call to the web service with the Accept
request header set to text/csv
will return csv formatted output.
[RoutePrefix("api")]
public class MainController : ApiController
{
[Route("Cars")]
public List<Car> GetCars()
{
var cars = new List<Car>();
cars.Add(new Car { Make = "Chevy", Year = 2004});
cars.Add(new Car { Make = "Ford", Year = 2005});
return cars;
}
}
[JsonObject]
public class Car
{
[JsonProperty(PropertyName = "make", Order = 1)]
public string Make { get; set; }
[JsonProperty(PropertyName = "year", Order = 0)]
public int Year { get; set; }
}
Same can be achieved if the method returns a HttpResponseMessage
. Code shown is based on How Content Negotiation Works
[Route("CarsFile")]
public HttpResponseMessage GetCarsFile()
{
var cars = new List<Car>();
cars.Add(new Car { Make = "Chevy", Year = 2004});
cars.Add(new Car { Make = "Ford", Year = 2005});
var negotiator = this.Configuration.Services.GetContentNegotiator();
var result = negotiator.Negotiate(typeof(List<Car>),
this.Request,
this.Configuration.Formatters);
// no formatter found
if (result == null)
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.NotAcceptable));
}
var response = new HttpResponseMessage
{
Content = new ObjectContent<List<Car>>(
cars, // data
result.Formatter, // media formatter
result.MediaType.MediaType // MIME type
)
};
// add the `content-disposition` response header
// to display the "File Download" dialog box
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = "cars-download." + GetFileExt(result.Formatter);
};
return response;
}
private string GetFileExt(MediaTypeFormatter formatter)
{
if (formatter is JsonMediaTypeFormatter)
{
return "json";
}
if (formatter is CsvMediaTypeFormatter)
{
return "csv";
}
// default to text
return "txt";
}
Related:
http://www.vickram.me/ienumerable-to-csv-extension-method
http://www.asp.net/web-api/overview/formats-and-model-binding/content-negotiation