Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
12
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

【C#】ASP.NET Core で CSV ファイルを返す Web API を作る

概要

ASP.NET CoreWeb APIを開発しクライアントにCSVファイルを返すエンドポイントを作ってみます。
TODOアプリでDBから取得したTODO一覧をCSVファイルとしてダウンロードできる機能を想定します。

プロジェクト構築

.NET Core CLIでプロジェクトのひな型を構築します。

# .NET Core SDK バージョンを確認
$ dotnet --version
2.1.502

# Web API プロジェクトを生成
$ dotnet new web api -o WebApiCsv

$ cd WebApiCsv
# CsvHelperパッケージをインストール
$ dotnet add package CsvHelper

csprojファイルは以下の通りです。

WebApiCsv.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <!--ついでに言語バージョンを C#7.3 に変更-->
    <LangVersion>7.3</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="CsvHelper" Version="12.1.2" />
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
  </ItemGroup>

</Project>

開発

Todoモデルを作成します。

Models/Todo.cs
namespace WebApiCsv.Models {
  public class Todo {
    public int ID { get; set; }
    public string Title { get; set; }
    public bool IsDone { get; set; }
  }
}

データ取得を行うリポジトリを作成します。
今回は実際にDBにアクセスせず、ダミーデータを返します。

Data/TodoRepository.cs
using System.Collections.Generic;
using WebApiCsv.Models;

namespace WebApiCsv.Data {
  public class TodoRepository {
    // ダミーデータ
    static List<Todo> todos { get; } = new List<Todo> {
      new Todo { ID = 1, Title = "CSV返却の記事", IsDone = false },
      new Todo { ID = 2, Title = "IoCの記事", IsDone = false },
    };

    public List<Todo> List() => this.todos;
  }
}

Todo一覧CSVデータを取得するサービスクラスを作成します。

Services/TodoService.cs
using CsvHelper;
using System.Collections.Generic;
using System.IO;
using WebApiCsv.Data;
using WebApiCsv.Models;

namespace WebApiCsv.Services {
  public class TodoService {
    // サンプルなので DI せず直にインスタンス化
    readonly TodoRepository repository = new TodoRepository();

    public byte[] GetCsvContents() {
      List<Todo> todos = repository.List();

      using (var memory = new MemoryStream())
      using (var writer = new StreamWriter(memory))
      using (var csv = new CsvWriter(writer)) {
        csv.WriteRecords(todos);
        writer.Flush(); //StreamWriter.Flush を呼ばないとバッファーからメモリに書き込まれないので注意
        return memory.ToArray();
      }
    }
  }
}

最後にリクエストを受け付けるControllerクラスを作成します。

Controllers/TodosController.cs
using Microsoft.AspNetCore.Mvc;
using System;
using WebApiCsv.Services;

namespace WebApiCsv.Controllers {
  [Route("api/[controller]")]
  [ApiController]
  public class TodosController : ControllerBase {
    // サンプルなので DI せず直にインスタンス化
    readonly TodoService service = new TodoService();

    [HttpGet("export")]
    public FileContentResult Export() {
      byte[] csv = service.GetCsvContents();
      string fileName = $"ToDoList-{DateTime.Now:yyyyMMdd_HHmmss}.csv";
      return File(csv, "text/csv", fileName);
    }
  }
}

サーバーを立ち上げます。

$ dotnet run
Hosting environment: Development
Content root path: ~/WebApiCsv
Now listening on: https://localhost:5001
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

https://localhost:{ポート番号}/api/todos/exportにアクセスするとCSVファイルをダウンロードできます。

ToDoList-20190216_000315.csv
ID,Title,IsDone
1,CSV返却の記事,False
2,IoCの記事,False

項目をダブルクォートで囲む

Services/TodoServiceから抜粋
  public byte[] GetCsvContents() {
    List<Todo> todos = repository.List();

    using (var memory = new MemoryStream())
    using (var writer = new StreamWriter(memory))
    using (var csv = new CsvWriter(writer)) {
+     csv.Configuration.ShouldQuote = (field, context) => true;
      csv.WriteRecords(todos);
      writer.Flush();
      return memory.ToArray();
    }
  }
}
ToDoList-20190222_010807.csv
"ID","Title","IsDone"
"1","CSV返却の記事","False"
"2","IoCの記事","False"

ヘッダーのカラム名を変えたい

Models/Todo.cs
+ using CsvHelper.Configuration.Attributes;

  namespace WebApiCsv.Models {
    public class Todo {
      public int ID { get; set; }

+     [Name("タイトル")]
      public string Title { get; set; }

+     [Name("済")]
      public bool IsDone { get; set; }
    }
  }
ToDoList-20190222_011222.csv
"ID","タイトル","済"
"1","CSV返却の記事","False"
"2","IoCの記事","False"
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
12
Help us understand the problem. What are the problem?