Andy N
Andy N

Reputation: 1304

C# Streaming to HTTP Response as CSV

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

Answers (1)

Andy N
Andy N

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

Related Questions