如何从ASP.NET Core导出CSV文件

Roh*_*ude 2 c# export-to-csv asp.net-core-mvc csv-write-stream

我正在尝试将代码从ASP.net迁移到ASP.net核心。

就像下面的ASP.net代码一样,

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;
Run Code Online (Sandbox Code Playgroud)

但是在ASP.NET核心中使用它时,我将其转换为

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;
Run Code Online (Sandbox Code Playgroud)

在ASP.net中Response.Output可用,但在核心中不可用。所以我试图像Response.Body

谁能告诉我,我做错了什么?

sob*_*ito 6

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");
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

感谢将数据从控制器导出到 CSV


Nko*_*osi 5

考虑更改方法以更符合当前建议的语法。

构造CSV并返回FileResult,这使代码不必直接操纵Response对象。

[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();
    var writeFile = new StreamWriter(stream);
    var csv = new CsvWriter(writeFile);
    csv.Configuration.RegisterClassMap<GroupReportCSVMap>();

    csv.WriteRecords(reportCSVModels);

    stream.Position = 0; //reset stream
    return File(stream, "application/octet-stream", "Reports.csv");
}
Run Code Online (Sandbox Code Playgroud)

  • 我发现如果您不在 csv.WriteRecords(reportCSVModels) 之后添加 writeFile.Flush(),则 CSV 文件最终会为空。 (3认同)
  • @jdoer1997 好收获。将 writer 包装在 using 块中也会在被处置之前将其刷新。 (2认同)
  • 这种方法是否意味着整个 csv 在创建时有助于记忆? (2认同)