LoginSignup
4

More than 3 years have passed since last update.

macOSでASP .NET Coreを使ってAPIサーバをHerokuにデプロイする

Last updated at Posted at 2020-07-31

macOSで.NET Coreを使ってAPIサーバをHerokuにデプロイするまでの手順をまとめます。

前提条件

実行環境は macOS Catalina です。
以下のツールはインストール済みとします。

  • VS Code
  • Docker

何を作るの?

シンプルなTodo管理APIサーバを構築します。データはデータベースに保存します。

.NET Core macOS版のインストール

Microsoftのウェブサイトからダウンロードしてインストールします。

必要な.NETツールをインストール

dotnet tool install --global dotnet-aspnet-codegenerator
dotnet tool install --global dotnet-ef

プロジェクトの作成

webapiテンプレートを使ってプロジェクトを作成します。
--no-httpsをつけないと、デフォルトでlocalhostの証明書を作る流れになってややこしくなります。

dotnet new webapi -o TodoApi --no-https

初期パッケージのインストール

Entity Framework Coreを使って、データベースへの書き込みを実現するので、以下のようにパッケージをインストールします。
ただ、今回はSQLiteだけ使うので、Microsoft.EntityFrameworkCore.Sqlite だけインストールしても問題ありません。

cd TodoApi
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.InMemory

初回起動

dotnet run で起動できます。

dotnet run

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/XXXXX/TodoApi

その後、curlを以下のように実行するとテンプレートの初期設定であるWeatherForecastの情報が取得できます。

curl http://localhost:5000/WeatherForecast

次のようなJSONが返されます。

[
   {
      "date" : "2020-08-01T08:48:53.47458+09:00",
      "summary" : "Mild",
      "temperatureC" : 39,
      "temperatureF" : 102
   },
   {
      "date" : "2020-08-02T08:48:53.474598+09:00",
      "summary" : "Mild",
      "temperatureC" : -20,
      "temperatureF" : -3
   },
   {
      "date" : "2020-08-03T08:48:53.474609+09:00",
      "summary" : "Scorching",
      "temperatureC" : 47,
      "temperatureF" : 116
   },
   {
      "date" : "2020-08-04T08:48:53.474619+09:00",
      "summary" : "Scorching",
      "temperatureC" : 54,
      "temperatureF" : 129
   },
   {
      "date" : "2020-08-05T08:48:53.474629+09:00",
      "summary" : "Sweltering",
      "temperatureC" : 39,
      "temperatureF" : 102
   }
]

モデルクラス TodoItem の追加

以下のようにTodoItem.csファイルをModelsフォルダの下に作成します。

TodoItem.cs
public class TodoItem
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

データベースコンテキストの追加

同様にModelsフォルダの下にTodoContext.csを作成します。

TodoContext.cs
using Microsoft.EntityFrameworkCore;

namespace TodoApi.Models
{
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }

        public DbSet<TodoItem> TodoItems { get; set; }
    }
}

Startup.cs を修正

Startup.csを以下のように修正します。ここで先ほど作成したモデルクラスやデータベースコンテキストを登録します。
今回は、SQLiteを使うのでそれ以外をコメントアウトしています。

Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

// 追加
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                //opt.UseInMemoryDatabase("TodoList"));
                opt.UseSqlite("Filename=db.sqlite3"));  // 今回はこれを使う。 SQLiteのファイル名は db.sqlite3
                //opt.UseNpgsql("Host=localhost;Database=mydb;Port=15432;Username=user;Password=password")); // PosgreSQL
                //opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); // SQL Server

            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

コントローラを生成

必要なパッケージを追加します。

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design

コントローラTodoItemsControllerを生成します。

dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

この状態で自動的にTodoItemのCRUD APIが実装されます。

データベースマイグレーションとデータベースの更新

dotnet ef migrations add <どんな変更を加えたのかを表す任意の名称>という形でマイグレーションを作成します。
dotnet ef database updateでデータベースを更新します。

dotnet ef migrations add InitialCreate
dotnet ef database update

APIを試してみる

dotnet runでサーバを起動します。

POSTのテスト

curl -X POST \
     -H "Content-Type:application/json" \
     -d '{"Name":"Task 01", "IsComplete":false}' \
     http://localhost:5000/api/TodoItems

curl -X POST \
     -H "Content-Type:application/json" \
     -d '{"Name":"Task 02", "IsComplete":false}' \
     http://localhost:5000/api/TodoItems

GETのテスト:一覧取得

curl http://localhost:5000/api/TodoItems
[{"id":1,"name":"Task 01","isComplete":false},{"id":2,"name":"Task 02","isComplete":false}]

PUTのテスト

curl -X PUT \
     -H "Content-Type:application/json" \
     -d '{"Id":2, "IsComplete":true}' \
     http://localhost:5000/api/TodoItems/2

GETのテスト:特定レコードの取得

curl http://localhost:5000/api/TodoItems/2
{"id":2,"name":"Task 02","isComplete":true}

DELETEのテスト

curl -X DELETE \
     -H "Content-Type:application/json" \
     http://localhost:5000/api/TodoItems/2
{"id":2,"name":"Task 02","isComplete":true}

TodoItemにカラムを追加

以下のようにTodoItemCreatedAtを追加します。

TodoItem.cs
using System;  // 追加

public class TodoItem
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
    public DateTime CreatedAt { get; set; } // 追加
}

以下のようにマイグレーションを実行します。

dotnet ef migrations add AddDateColumn
dotnet ef database update

データベースが更新されたことを確認

sqlite db.sqlite3
sqlite> PRAGMA table_info('TodoItems');
0|Id|INTEGER|1||1
1|Name|TEXT|0||0
2|IsComplete|INTEGER|1||0
3|CreatedAt|TEXT|1|'0001-01-01 00:00:00'|0
sqlite> 

Herokuへデプロイ

以下のようなDockerfileを作ります。

Dockerfile
FROM mcr.microsoft.com/dotnet/core/aspnet

COPY bin/Release/netcoreapp3.1/publish/ App/
WORKDIR /App

CMD export ASPNETCORE_URLS=http://0.0.0.0:$PORT; dotnet TodoApi.dll

デプロイファイルを生成します。
bin/Release/netcoreapp3.1/ 配下にリリースようファイル群が生成されます。

dotnet publish -c Release

Herokuのインスタンスを作成して、Dockerfileをpush & releaseします。

heroku create 
heroku container:login
heroku container:push web --app <appName>
heroku container:release web --app <appName>

参考

チュートリアル: ASP.NET Core で Web API を作成する
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.1&tabs=visual-studio-code#prerequisites

チュートリアル: 移行機能の使用 - ASP.NET MVC と EF Core
https://docs.microsoft.com/ja-jp/aspnet/core/data/ef-mvc/migrations?view=aspnetcore-3.1

チュートリアル: JavaScript を使用して ASP.NET Core Web API を呼び出す
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/web-api-javascript?view=aspnetcore-3.1

ASP.NET Core を使って Web API を作成する
https://docs.microsoft.com/ja-jp/aspnet/core/web-api/?view=aspnetcore-3.1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4