Reputation: 1304
I would like my c# MVC Controller to stream back results from my repository to a CSV.
I've seen some examples of this using a FileResult
, however those approaches appear to rely on the entire content of the file being held in-memory as a byte array. The CSVs I'm dealing with will potentially be large and I would like to avoid storing them in memory by streaming them straight through.
This answer shows both examples. I began by implementing my endpoint to stream records through to the endpoint:
[HttpGet("download")]
public async IAsyncEnumerable<Foo> StreamDownload() {
IAsyncEnumerable<Foo> foos = fooRepository.getAll();
await foreach(Foo foo in foos) {
yield return convertToDto(foo);
}
}
However when attempting to create a custom formatter using this guide, I found that HttpResponses now use a PipeWriter to handle their I/O connections.
I'm in the process of attempting to create a custom formatter which will read from the IAsyncEnumerable and write to the PipeWriter. However, as this strikes me as a common enough problem, I thought it was worth checking if:
Upvotes: 1
Views: 1578
Reputation: 1304
I was able to use this NuGet package to handle the CSV serialization: https://www.nuget.org/packages/WebApiContrib.Core.Formatter.Csv/
Just add the serializer to services:
var csvOptions = new CsvFormatterOptions {
UseSingleLineHeaderInCsv = true,
CsvDelimiter = ",",
IncludeExcelDelimiterHeader = true
};
services.AddMvc().AddCsvSerializerFormatters(csvOptions);
..and tag the method as returning CSV:
[HttpGet("download")]
[Produces("text/csv")]
public async IAsyncEnumerable<Foo> StreamDownload() {
IAsyncEnumerable<Foo> foos = fooRepository.getAll();
await foreach(Foo foo in foos) {
yield return convertToDto(foo);
}
}
Upvotes: 1