C# Creating a Custom FileResult to Export Data into a CSV file Using Streaming in a .NET Core 3.1 MVC App
Tags: csharp, dotnet, webdev
Published: 2020-05-22 11:59:04

## Introduction: What is the goal?

In the past two months at work, I was tasked with learning C#, as well as creating a web app using the .NET Core 3.1 MVC framework. I wanted to document the most interesting concepts in a series of blog posts.

In this blog, I will show you how to create a custom fileresult to export data into a CSV file using streaming in a .NET Core 3.1 MVC web app. This came about as I was asked to give the user the ability to export their dataset into a CSV file through the web app, but there was a lot of data to deal with. The goal here was to create something to export to a CSV file taking performance into account.

The actual code was more complex; this blog is my attempt to abstract the core concepts into a simple web app using Pusheen the Cat as a fun example!

P.S. If you don't know who Pusheen is, I am utterly obsessed with it. You'll probably recognise Pusheen from numerous gifs and stickers on social media.


## C# Streaming: What is it and why is it useful?

Imagine you had a lot of data to read/write as part of a web app solution; you probably want to break it down into bitesize pieces, as you won't want to read/write a large file in one go! This can be achieved through streaming.

A stream sits between the application and the file; the benefit of using streaming is the read/write operations are a lot smoother. When you're writing data to somewhere, it is written to the stream and then from the stream, it then goes to your chosen destination, usually a file. When you're reading data, you read to the stream and then your web app can then read from the stream.

If you like to read on a bit more, this [article][1] by Guru99 is particularly helpful.


"C# provides standard IO (Input/Output) classes to read/write from different sources like a file, memory, network, isolated storage, etc. **System.IO.Stream** is an abstract class that provides standard methods to transfer bytes (read, write, etc.) to the source. It is like a wrapper class to transfer bytes. Classes that need to read/write bytes from a particular source must implement the Stream class." - Extracted from [TutorialsTeacher][2]


## Creating a Custom FileResult With Streaming in .NET Core 3.1

### Why Create a Custom Fileresult in the First Place?

The .NET Core 3.1 MVC framework provides the **ActionResult** class. Here's the [link][3] to the docs for it. It implements the **IActionResult** interface. ActionResult is essentially the return type of a controller method, it is the base class for lots of result classes to return models to views, file streams and more! There are many derived classes to choose from, but there wasn't one to produce a CSV result. I wanted a **FileResult** which has streaming and exported to CSV.

The cool thing was one of the derived classes is **FileResult**. This class represents an **ActionResult** that when executed will write a file as the response. We can extend on this class to create a custom **FileResult** to create a CSV **FileResult**.

## Example of Custom FileResult With Streaming in .NET Core 3.1

Here is an example of a **PusheenCsvResult** which extends **FileResult**. As it is specific to exporting data about Pusheen the Cat, we give it some **pusheenData** as **IEnumerable<Pusheen>**. In it's constructor, we pass in that data along with the **fileDownloadName** and set the file type to be **"text/csv"**.

As we're extending on **FileResult**, we override **ExecuteResultAsync** with our implementation. In this example, we're using **StreamWriter** to write to the response body of the **HttpContext** of the **ActionContext**. We write the header row for our CSV file and then iterate through our **_pusheenData** and write that data. As a reminder, the stream sits in between the application and in this case the response body; the data is written to the stream (response body) and then from the stream, it then results in the CSV file being produced.

We define the StreamWriter within a **using** block. We use **StreamWriter.FlushAsync** method to clear all buffers for the current writer and results in any buffered data to be written to the underlying stream.


```csharp

using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;


namespace PusheenCustomExportCsv.Web.Models
{
    public class PusheenCsvResult : FileResult
    {
        private readonly IEnumerable<Pusheen> _pusheenData;

        public PusheenCsvResult(IEnumerable<Pusheen> pusheenData, string fileDownloadName) : base("text/csv")
        {
            _pusheenData = pusheenData;
            FileDownloadName = fileDownloadName;
        }

        public async override Task ExecuteResultAsync(ActionContext context)
        {
            var response = context.HttpContext.Response;
            context.HttpContext.Response.Headers.Add("Content-Disposition", new[] { "attachment; filename=" + FileDownloadName });

            using (var streamWriter = new StreamWriter(response.Body)) {
              await streamWriter.WriteLineAsync(
                $"Pusheen, Food, SuperPower"
              );
              foreach (var p in _pusheenData)
              {
                await streamWriter.WriteLineAsync(
                  $"{p.Name}, {p.FavouriteFood}, {p.SuperPower}"
                );
                await streamWriter.FlushAsync();
              }
              await streamWriter.FlushAsync();
            }
        }

    }
}

```

## Using the Custom FileResult in the Controller

Now that we have the **PusheenCsvResult** class, we can go ahead and use it in the controller.

```csharp

#The rest of the code has been omitted for brevity! :)

public FileResult ExportCsv()
{
    return File(_pusheenService.GetAllPusheens(), "pusheen.csv");
}

public virtual PusheenCsvResult File(IEnumerable<Pusheen> pusheenData, string fileDownloadName)
{
    return new PusheenCsvResult(pusheenData, fileDownloadName);
}

```

## App Demo

Here's some screenshots of what it looks like from the front-end!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g1z9euq4gwwsqhpfalxu.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f65oguxkv9sd6784436i.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ao0w1wonitnmztlclwl0.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b519ge6volnaea22dsz0.png)


## Final Thoughts

I hope you found this useful! I thought an improvement for this **PusheenCsvResult** class would be to make it **generic**, so that it can work with all kinds of datasets, not just the Pusheen dataset! That's for another day! :)

Watch out for my next blog on unit testing the Custom FileResult which Exports Data into a CSV file Using Streaming in a .NET Core 3.1 MVC App. I have a series of .NET Core MVC blogs coming up, so it should be exciting times!

Thank you for reading my blog! :)


## Link to Github Repo

You can find the link to my Github repo with the simple web app example containing the custom fileresult [here][4].


[1]: https://www.guru99.com/c-sharp-stream.html
[2]: https://www.tutorialsteacher.com/csharp/csharp-stream-io
[3]: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.actionresult?view=aspnetcore-3.1
[4]: https://github.com/kimdiep/pusheen-custom-fileresult-csv-export-aspnetcore