Search code examples
c#asp.net-core-mvcexport-to-csvcsv-write-stream

How to Export CSV file from ASP.NET core


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?


Solution

  • 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");
    }