0

I want to return a csv file to a website from an object list.

The process starts with retrieving json data from a database, convert it to a list of objects and print it to a csv file. I currently have no idea to how I should return the file, currently I save it to my own hdd (just to make sure it works like I wanted it to).

Class for the function to write the csv:

public void WriteCSV<T>(IEnumerable<T> items, string path)
{
    Type itemType = typeof(T);
    var props = itemType.GetProperties(BindingFlags.Public |
    BindingFlags.Instance)
                        .OrderBy(p => p.Name);

    using (var writer = new StreamWriter(path))
    {
        writer.WriteLine("sep=,");
        writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));

        foreach (var item in items)
        {
            writer.WriteLine(string.Join(", ", props.Select(p =>
            p.GetValue(item, null))));
        }
    }
}

Class to call the method and runt the file to the user:

public List<jsonObj> dataList = new List<jsonObj>();
[HttpGet]
[Route("api/csv/{id}")]
public IActionResult getCsv(int id)
{

    var client = new HttpClient();

    var json = client.GetStringAsync("http://localhost:52716/api/csv/data/" + id).Result;

    dataList = JsonConvert.DeserializeObject<List<jsonObj>>(json);


    WriteCSV(dataList, @"C:\Users\****\Desktop\min.csv");
    return Ok();
    //return File(csv, "text /csv", "results.csv");
}
VDWWD
  • 35,079
  • 22
  • 62
  • 79
Jesper.Lindberg
  • 313
  • 1
  • 5
  • 14
  • 1
    You might want to use a specialized library for creating CSV: https://joshclose.github.io/CsvHelper/ – VDWWD Mar 10 '18 at 10:11
  • @VDWWD I tried it but it made me even more confused. – Jesper.Lindberg Mar 10 '18 at 10:13
  • @VDWWD I disagree, see below. – Ole EH Dufour Mar 10 '18 at 10:27
  • For asp.net core see https://stackoverflow.com/questions/47423563/how-can-i-return-a-csv-file-in-asp-net-core-2 – Ole EH Dufour Mar 10 '18 at 10:33
  • 1
    @OleEHDufour, Really? In your snippet you have to specify each columns separately and if you add a property you have to change `string line = ` manually also. And what about error handling and escaping characters? Tested your snippet and it generates incorrect csv if the string has `"` in it. – VDWWD Mar 10 '18 at 10:35
  • @VDWWD Sorry for misreading your comment, I was under the impression that one can't do without this CsvHelper. Your solution might be more elegant. – Ole EH Dufour Mar 10 '18 at 10:47
  • @OleEHDufour, you are indeed correct that you can do without. But it becomes a whole lot easier, error proof and maintainable once you start using a library. This goes for other items as well like Newtonsoft.JSON for json files and EPPplus to generate excel documents. – VDWWD Mar 10 '18 at 11:38
  • I sure could have used a library, I tried CsvExport but that one made the csv really messy. Therefore this solution was really nice and simple. – Jesper.Lindberg Mar 10 '18 at 11:57

1 Answers1

2

Here a snippet with the library I mentioned. Just input MyList as your List with objects and you're done. Once you have a byte array you can send it to the browser, store it in the DB etc.

using CsvHelper;

byte[] bin;

using (MemoryStream stream = new MemoryStream())
using (TextWriter textWriter = new StreamWriter(stream))
using (CsvWriter csv = new CsvWriter(textWriter))
{
    csv.Configuration.QuoteAllFields = true;
    csv.Configuration.TrimHeaders = true;
    csv.Configuration.TrimFields = true;

    csv.WriteRecords(MyList);
    bin = stream.ToArray();
}

Response.ClearHeaders();
Response.Clear();
Response.Buffer = true;
Response.ContentType = "text/csv; charset=utf-8";
Response.AppendHeader("Content-disposition", string.Format("attachment; filename=\"{0}\"", "MyFile.csv"));
Response.AppendHeader("Content-Length", bin.Length.ToString());
Response.BinaryWrite(bin);
Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
VDWWD
  • 35,079
  • 22
  • 62
  • 79