概要
ASP.NET Core
でWeb 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"