使用 asp.net core webapi 导出数据文件

发布于:2025-06-29 ⋅ 阅读:(14) ⋅ 点赞:(0)

本篇文章我们讲解如何使用 ASP.NET Core WebAPI 导出数据文件。

项目准备

1. 创建 Web API 项目

要使用 .NET CLI 创建一个 Web API 项目,请运行以下命令:

dotnet new webapi -o ExportDataFile
  • webapi:模板类型,用于创建 Web API 项目。
  • -o ExportDataFile:指定生成的项目文件夹名称。

创建完成后,进入项目目录并启动开发服务器:

cd ExportDataFile
dotnet run

你的 Web API 应用将在默认端口(如 https://localhost:5001)运行。

要使用 ASP.NET Core Web API 导出数据文件,可以按照以下步骤操作:


2. 定义数据模型

确保 WeatherForecast 类已经定义,例如:

public sealed class WeatherForecast
{
    public DateOnly Date { get; set; }
    public int TemperatureC { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    public string? Summary { get; set; }
}

在你的代码中,还应该有一个字符串数组 Summaries,比如:

private static readonly string[] Summaries =
[
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
];

模拟数据源,方法如下:

private IEnumerable<WeatherForecast> GetWeatherForecasts(int count) => Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
    Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
    TemperatureC = Random.Shared.Next(-20, 55),
    Summary = Summaries[Random.Shared.Next(Summaries.Length)]
});

导出文件示例

1. 创建导出接口(CSV 示例)

你可以添加一个 API 接口,将数据以 CSV 文件的形式返回。示例代码如下:

using ClosedXML.Excel;
using ExportDataFile.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using System.IO.Compression;
using System.Net.Mime;
using System.Text;
using System.Text.Json;

[ApiController]
[Route("weather_forecast")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet("data/export/csv")]
    public IActionResult ExportCsv()
    {
        var data = GetWeatherForecasts(5);

        string fileName = $"{Guid.NewGuid()}.data.csv";
        string contentType = $"{MediaTypeNames.Text.Csv};charset=UTF-8";

        // 构建 CSV 内容
        StringBuilder csv = new();
        csv.AppendLine("Date,TemperatureC,TemperatureF,Summary");
        foreach (var item in data)
        {
            csv.AppendLine($"{item.Date},{item.TemperatureC},{item.TemperatureF},{item.Summary}");
        }

        // 返回 CSV 文件
        byte[] fileBytes = Encoding.UTF8.GetBytes(csv.ToString());
        return File(fileBytes, contentType, fileName);
    }
}

说明:后续的示例均在该控制器里面实现,为了方便拆分讲解,因此只把单个方法提取讲解。


2. 支持其他格式(可选)

如果你希望支持 Excel 格式,可以通过 NuGet 安装如 EPPlusClosedXML 等库,并生成 .xlsx 文件。

安装 nuget 包:

dotnet add package ClosedXML --version 0.105.0
示例:使用 ClosedXML 生成 Excel 文件
[HttpGet("data/export/excel")]
public IActionResult ExportExcel()
{
    var data = GetWeatherForecasts(5);

    string fileName = $"{Guid.NewGuid()}.data.xlsx";
    string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8";

    using (var workbook = new XLWorkbook())
    {
        var worksheet = workbook.Worksheets.Add("WeatherForecasts");
        worksheet.Cell(1, 1).Value = "Date";
        worksheet.Cell(1, 2).Value = "TemperatureC";
        worksheet.Cell(1, 3).Value = "TemperatureF";
        worksheet.Cell(1, 4).Value = "Summary";

        int row = 2;
        foreach (var item in data)
        {
            worksheet.Cell(row, 1).Value = item.Date.ToString();
            worksheet.Cell(row, 2).Value = item.TemperatureC;
            worksheet.Cell(row, 3).Value = item.TemperatureF;
            worksheet.Cell(row, 4).Value = item.Summary;
            row++;
        }

        using var stream = new MemoryStream();
        workbook.SaveAs(stream);
        var content = stream.ToArray();
        return File(content, contentType, fileName);
    }
}

3. 创建导出接口(JSON 示例)

下面介绍两种示例,分别使用 GzipZIP 压缩文件,使用 FileStreamResult 流式返回。

3.1 示例:使用 Gzip 流式压缩
/// <summary>
/// 导出 data 的 json 文件
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
[HttpGet("/data/{count}/export/gzip")]
public async Task<IActionResult> ExportGzipAsync([FromRoute] int count)
{
    logger.LogInformation("开始获取数据");

    // 1. 模拟获取数据
    var data = GetWeatherForecasts(count);

    string fileName = $"{Guid.NewGuid()}.data.json.gz";
    string contentType = $"{MediaTypeNames.Application.GZip};charset=UTF-8";

    // 2. 创建内存流和压缩流,确保在 FileStreamResult 使用前保持打开
    MemoryStream memoryStream = new();
    using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal, leaveOpen: true)) // ⚠️ 关键:leaveOpen: true
    using (var streamWriter = new StreamWriter(gzipStream))
    {
        var json = JsonSerializer.Serialize(data);
        await streamWriter.WriteAsync(json);
        await streamWriter.FlushAsync();
    }

    // 重置流位置
    memoryStream.Seek(0, SeekOrigin.Begin);

    // 3. 构造响应头
    Response.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    {
        FileName = fileName
    }.ToString();

    Response.Headers.ContentEncoding = "gzip";

    // 4. 使用 FileStreamResult 流式返回
    return new FileStreamResult(memoryStream, contentType)
    {
        FileDownloadName = fileName
    };
}
3.2 示例:使用 ZIP 压缩
[HttpGet("/data/{count}/export/zip")]
public async Task<IActionResult> ExportZipAsync([FromRoute] int count)
{
    logger.LogInformation("开始获取数据");

    // 1. 模拟获取数据
    var data = GetWeatherForecasts(count);

    string fileName = $"{Guid.NewGuid()}.data.json.zip";
    string contentType = $"{MediaTypeNames.Application.Zip};charset=UTF-8";

    // 2. 创建内存流并写入 ZIP 压缩内容
    MemoryStream memoryStream = new();

    using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, leaveOpen: true))
    {
        var jsonEntry = archive.CreateEntry("agent_team.json"); // 在 ZIP 中创建一个文件条目

        using (var entryStream = jsonEntry.Open())
        using (var streamWriter = new StreamWriter(entryStream))
        {
            var json = JsonSerializer.Serialize(data);
            await streamWriter.WriteAsync(json);
            await streamWriter.FlushAsync();
        }
    }

    // 重置流位置,确保从头读取
    memoryStream.Seek(0, SeekOrigin.Begin);

    // 3. 构造响应头
    Response.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    {
        FileName = fileName
    }.ToString();

    Response.Headers.ContentEncoding = "zip";

    // 4. 使用 FileStreamResult 流式返回
    return new FileStreamResult(memoryStream, contentType)
    {
        FileDownloadName = fileName
    };
}
3.3 Gzip & ZIP 的区别

GzipZIP 都是常用的文件压缩格式,但它们在使用场景、压缩方式和功能上有显著的区别。以下是两者的主要对比:

特性 Gzip ZIP
压缩对象 通常用于单个文件的压缩 支持多个文件和目录的打包与压缩
压缩算法 使用 DEFLATE 算法 同样使用 DEFLATE 算法(也可支持其他)
文件结构 只能压缩单个文件 可以压缩多个文件并保留目录结构
跨平台支持 Unix 系统原生支持(如 Linux、macOS),Windows 需借助第三方工具(如 7-Zip 所有主流操作系统(Windows、Linux、macOS)均原生支持
压缩效率 压缩率较高 压缩率与 Gzip 相当
使用场景 Linux/Unix 系统下的日志压缩、备份等 Windows 用户常用,适合打包项目源码等
命令行工具 gzip, gunzip zip, unzip
是否支持加密 不支持 支持密码保护
兼容性 Web 传输中广泛使用(HTTP 压缩) 更适用于通用文件分发、跨平台共享
总结
  • 如果你只需要压缩一个文件并且注重压缩率和速度,尤其是类 Unix 环境下,可以选择 Gzip
  • 如果你需要压缩多个文件或目录,并且希望保留文件结构,或者需要跨平台兼容性和加密功能,则更适合使用 ZIP

4. 测试 API

启动项目后,访问以下 URL 来测试导出功能:

  • CSVhttp://localhost:5000/data/export/csv
  • Excelhttp://localhost:5000/data/export/excel
  • Gziphttp://localhost:5000/data/{count}/export/gzip
  • ZIPhttp://localhost:5000/data/{count}/export/zip

说明:浏览器会自动下载对应的文件。

使用 curl 访问举例:

curl -X 'GET' \
  'http://localhost:5000/data/5/export/zip' \
  -H 'accept: application/octet-stream' \

Response body

  • Download file

Response headers

 content-disposition: attachment; filename=96dbfeec-7473-47f2-ac18-a784063ebbac.data.json.zip; filename*=UTF-8''96dbfeec-7473-47f2-ac18-a784063ebbac.data.json.zip 
 content-encoding: zip 
 content-length: 272 
 content-type: application/zip; charset=UTF-8 
 date: Fri,27 Jun 2025 08:30:33 GMT 
 server: Kestrel 

5. 部署和优化

  • 如果是生产环境,请考虑分页、性能优化以及日志记录。
  • 可以根据需求扩展为 PDF、JSON 下载等不同格式。
  • 对于大文件导出,建议使用异步方式或后台任务处理。

通过以上步骤,你就可以使用 ASP.NET Core Web API 实现数据的导出功能,并结合 GetWeatherForecasts 模拟数据源来生成所需的文件。