How to Export CSV file from ASP.NET core
Asked Answered
H

3

12

I am trying to migrate code from ASP.net to ASP.net core.

Where as in ASP.net code was like below,

var progresses = db.Progresses.Where(p => p.UserId == id).Include(p => p.User.UserMetaData).Include(p => p.Quiz).Include(p => p.User.Groups).OrderByDescending(p => p.UpdatedAt).ToList();

List<ReportCSVModel> reportCSVModels = new List<ReportCSVModel>();
const string downloadName = "Reports.csv";
var csv = new CsvWriter(Response.Output);

csv.Configuration.RegisterClassMap<ReportCSVMap>();

Response.ClearContent();

Response.ContentType = "application/octet-stream";

Response.AddHeader("Content-Disposition",
   "attachment; filename=" + downloadName);

csv.WriteHeader<ReportCSVModel>();
foreach (var progress in progresses)
{
    var reportCSVModel = new ReportCSVModel();
    reportCSVModel.Quiz = progress.Quiz.Title;
    reportCSVModel.Score = (progress.CorrectAnswersCount * progress.PointsPerQuestion).ToString();
    reportCSVModel.Status = progress.Status;
    reportCSVModel.CompletedDate = progress.UpdatedAt.ToString();
    reportCSVModel.Location = progress.User.UserMetaData != null ? progress.User.UserMetaData.Location : "";
    reportCSVModel.Group = progress.User.Groups.FirstOrDefault() != null ? progress.User.Groups.FirstOrDefault().Name : "";

    csv.WriteRecord<ReportCSVModel>(reportCSVModel);
}
Response.Flush();
Response.End();
return null;

But while using it in ASP.NET core, I Converted it like,

var progresses = _elearnContext.Progress.Where(p => p.UserId == id).Include(p => p.User.UserMetaData).Include(p => p.Quiz).Include(p => p.User.Groups).OrderByDescending(p => p.UpdatedAt).ToList();

// List<ReportCSVModel> reportCSVModels = new List<ReportCSVModel>();
List<ReportCSVModel> reportCSVModels = new List<ReportCSVModel>();
const string downloadName = "Reports.csv";

System.IO.TextWriter writeFile = new StreamWriter(Response.Body.ToString());
CsvWriter csv = new CsvWriter(writeFile);
csv.Configuration.RegisterClassMap<GroupReportCSVMap>();
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.Headers.Add("Content-Disposition", "attachment; filename=" + downloadName);


csv.WriteHeader<ReportCSVModel>();
foreach (var progress in progresses)
{
    var reportCSVModel = new ReportCSVModel();
    reportCSVModel.Quiz = progress.Quiz.Title;
    reportCSVModel.Score = (progress.CorrectAnswersCount * progress.PointsPerQuestion).ToString();
    reportCSVModel.Status = progress.Status;
    reportCSVModel.CompletedDate = progress.UpdatedAt.ToString();
    reportCSVModel.Location = progress.User.UserMetaData != null ? progress.User.UserMetaData.Location : "";
    reportCSVModel.Group = progress.User.Groups.FirstOrDefault() != null ? progress.User.Groups.FirstOrDefault().Name : "";

    csv.WriteRecord<ReportCSVModel>(reportCSVModel);
}

Response.Clear();
return null;

In ASP.net where Response.Output is available but its not available in core. So I tried to use it like Response.Body

Can Anybody tell me, where I did wrong?

Handshaker answered 10/10, 2018 at 13:37 Comment(0)
A
23

Consider changing approach to align more with current suggested syntax.

Construct the CSV and return a FileResult, which allows the code to not have to directly manipulate the Response object.

[HttpGet]
public IActionResult MyExportAction() {
    var progresses = _elearnContext.Progress.Where(p => p.UserId == id)
        .Include(p => p.User.UserMetaData)
        .Include(p => p.Quiz)
        .Include(p => p.User.Groups)
        .OrderByDescending(p => p.UpdatedAt)
        .ToList()
        .Select(progress => 
            new ReportCSVModel() {
                Quiz = progress.Quiz.Title,
                Score = (progress.CorrectAnswersCount * progress.PointsPerQuestion).ToString(),
                Status = progress.Status,
                CompletedDate = progress.UpdatedAt.ToString(),
                Location = progress.User.UserMetaData != null ? progress.User.UserMetaData.Location : "",
                Group = progress.User.Groups.FirstOrDefault() != null ? progress.User.Groups.FirstOrDefault().Name : ""
            }
        );

    List<ReportCSVModel> reportCSVModels = progresses.ToList();

    var stream = new MemoryStream();
    using(var writeFile = new StreamWriter(stream, leaveOpen: true)) {
        var csv = new CsvWriter(writeFile, true);
        csv.Configuration.RegisterClassMap<GroupReportCSVMap>();            
        csv.WriteRecords(reportCSVModels);
    }
    stream.Position = 0; //reset stream
    return File(stream, "application/octet-stream", "Reports.csv");
}
Analgesic answered 10/10, 2018 at 14:18 Comment(5)
I found that if you don't add writeFile.Flush() after csv.WriteRecords(reportCSVModels), the CSV file ends up empty.Serenata
@jdoer1997 good catch. wrapping the writer in a using block will also flush it before being disposed.Analgesic
Does this approach mean that the entire csv is being help in memory as it's being created?Guglielma
Is this is still up to date with current ASP .NET Core?Martinez
CsvHelper changed it's API, registering a class map is now csv.Context.RegisterClassMapSpecification
G
9
using CsvHelper;
using CsvHelper.Configuration;

namespace projectX.Controllers {
  [Route("MyController")]
  public class MyController : Controller {
    [Route("export")]
    [HttpGet]
    public ActionResult export() {
      var cc = new CsvConfiguration(new System.Globalization.CultureInfo("en-US"));
      using (var ms = new MemoryStream()) {
        using (var sw = new StreamWriter(stream: ms, encoding: new UTF8Encoding(true))) {
          using (var cw = new CsvWriter(sw, cc)) {
            cw.WriteRecords(YourGenericList);
          }// The stream gets flushed here.
          return File(ms.ToArray(), "text/csv", $"export_{DateTime.UtcNow.Ticks}.csv");
        }
      }
    }
  }
}

Thanks to Exporting data to CSV from Controller

Gauze answered 1/6, 2020 at 4:58 Comment(0)
M
1

//Install Package CsvHelper

//Controller Coding

    public async Task<IActionResult> indiainfected(ExcelDownloadIndiaInfected exceldownloadindiainfected)
    { 
        var excel =await downloadReportsRepository.ExcelSheetAddIndiaInfected(exceldownloadindiainfected);
        var cc = new CsvConfiguration(new System.Globalization.CultureInfo("en-US"));
        var stream = new MemoryStream();
        using (var sw = new StreamWriter(stream: stream, encoding: newUTF8Encoding(true)))
        {
            using (var cw = new CsvWriter(sw, cc))
            {
                cw.WriteRecords(excel);
            }
            
        }
        string csvName = $"India_Infected-{DateTime.UtcNow.Ticks}.csv";
        return File(stream.ToArray(), "text/csv", csvName);
    }
Messenger answered 15/7, 2020 at 6:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.