【初心者向け】C# + ASP.NET 8 .0のWeb API 開発環境を macOS Sonomaと Docker Desktop 4.32 で構築してみよう!

C# + ASP.NET 8 .0のWeb API 開発環境を macOS Sonomaと Docker Desktop 4.32 で構築してみよう!

記事の概要

この記事では、マイクロソフトが開発したプログラミング言語C#と ASP.NET Core 8.0を使って、macOS Sonoma と Docker Desktop 4.32 での開発環境の構築からシンプルなWeb API開発、実行までの流れを紹介します。

この記事を参考に、C#やWebAPI開発のスタートの一助となれば幸いです。


今回の記事の対象者

この記事は次のような方に向けています:

  • C#を使ってアプリ開発を始めたい方
  • macOSとDockerコンテナを使ってASP.NET Core8.0の開発環境を構築したい方
  • シンプルなWebAPIでC#の実装イメージを理解したい方

はじめに

今回は、構築する開発環境と、開発するWebAPIの概要は以下の通りです。

開発環境は、以下2つの環境を構築します。

  • ローカル環境
    • macOS Sonoma
    • ASP.NET Core 8.0 開発・実行環境
  • サーバー環境
    • Docker コンテナ on macOS Sonoma
    • ASP.NET Core 8.0 コンテナ開発・実行環境

WebAPIは、書籍情報を管理する簡易なライブラリ管理の機能を提供します。ライブラリ管理をオブジェクト指向プログラミングで開発し、C#の特徴とともにオブジェクト指向の基本的な考え方を学べるようにしています。

  • ライブラリ管理機能
    • データ取得
    • データ追加
    • データ更新
    • データ削除

また、作成したソースコードをもとに、アプリのポイントを詳しく解説していますので、是非この記事を活用してください。


もくじ


ソフトウェア・ハードウェア

必要なツール、ライブラリ、端末は以下の通りです。

開発ツール

以下、開発ツールとその公式サイトの一覧です。本記事ではVisual Studio Code(以下 VS Code)を使いますが、Jetbrains社のRiderは非常に高機能なので、導入しておくと開発作業が楽になります。

ツール名用途
VS CodeオープンソースのIDEです。色々なプラグインで環境を拡張できます。
Rider.NET開発者向けのIDEです。学生は無料となっています。

端末

以下、今回の環境を構築する対象の端末スペックです。

項目詳細
ハードウェアApple Silicon M3, RAM 24GB
OSmacOS Sonoma 14.6

本記事で紹介するソフトウェアおよびツールは、筆者の個人的な使用経験に基づくものであり、公式のサポート外の設定や使用方法を含む場合があります。利用に際しては、公式サイトの指示およびガイドラインを参照し、自己責任で行ってください。


C#、.NETとは

マイクロソフトが提供する強力な無料のオープンソースの開発プラットフォームで、いろいろな種類のマルチプラットフォームに対応したアプリケーションを作る事ができます。

学びやすい環境が整っているので、これからプログラミングを学ぶ初心者にとって、.NETはとても良い選択肢です。

C#:使いやすさとパワフルさを兼ね備えた言語で、初心者からプロフェッショナルまで幅広い開発者に利用されています。

.NET:さまざまな種類のアプリケーションを作るためのツールやライブラリが集まっています。WindowsやMac、Linux、さらにはスマートフォンやWebサイト、ゲームなど、いろいろな場所で動くソフトウェアを作るのに役立ちます。


ローカル環境の構築

macOSにC#と ASP.NET Core 8.0をインストールする手順は以下の通りです。

  • .NET SDKのダウンロード、インストール
  • Entity Framework Core ツールインストール
  • Visual Studio Codeのダウンロード、インストール
  • Visual Studio CodeへのC#拡張機能のインストール
  • NuGetのインストール
  • PostgreSQLのインストール
  • pgAdmin4のインストール

.NET SDKのダウンロード、インストール

.NETのダウンロードサイトへアクセスします。アクセスすると、画面中央にOSに適したバージョンのダウンロードボタンが表示されます。

今回は、「.NET SDK Arm64(Apple Silicon)のダウンロード」をクリックすると、インストーラがダウンロードされます。

ダウンロードディレクトリに「dotnet-sdk-8.0.401-osx-arm64.pkg」というファイルがあるのでダブルクリックし、インストールしてください。


Entity Framework Core ツールインストール

以下のコマンドを実行して、データベースのマイグレーションを支援するツールをインストールします。

dotnet tool install --global dotnet-ef
dotnet ef

インストール時の実行結果です。環境変数への追加を忘れずに行って下さい。

(base) xxxxxx@xxxxxx test-pj % dotnet tool install --global dotnet-ef
ツール ディレクトリ '/Users/xxxxxx/.dotnet/tools' は現在、PATH 環境変数にありません。
zsh を使用している場合、次のコマンドを実行してプロファイルに追加できます:

cat << \\EOF >> ~/.zprofile
# .NET Core SDK tools
export PATH="$PATH:/Users/xxxxxx/.dotnet/tools"
EOF

`zsh -l` を実行して現在のセッションで利用できるようにします。

これは、次のコマンドを実行することによってのみ、現行のセッションに追加できます:

export PATH="$PATH:/Users/xxxxxx/.dotnet/tools"

次のコマンドを使用してツールを呼び出せます。dotnet-ef
ツール 'dotnet-ef' (バージョン '8.0.8') が正常にインストールされました。
(base) xxxxxx@xxxxxx test-pj % 

コマンドを実行して、正しくインストールされていることを確認します。

(base) xxxxxx@xxxxxx test-pj % dotnet ef                             

                     _/\\__       
               ---==/    \\\\      
         ___  ___   |.    \\|\\    
        | __|| __|  |  )   \\\\\\   
        | _| | _|   \\_/ |  //|\\\\ 
        |___||_|       /   \\\\\\/\\\\

Entity Framework Core .NET Command-line Tools 8.0.8

Usage: dotnet ef [options] [command]

Options:
  --version        Show version information
  -h|--help        Show help information
  -v|--verbose     Show verbose output.
  --no-color       Don't colorize output.
  --prefix-output  Prefix output with level.

Commands:
  database    Commands to manage the database.
  dbcontext   Commands to manage DbContext types.
  migrations  Commands to manage migrations.

Use "dotnet ef [command] --help" for more information about a command.
(base) xxxxxx@xxxxxx test-pj % 

VS Codeのダウンロード、インストール

VS Codeの公式サイトへアクセスします。アクセスすると、画面右上にダウンロードボタンが表示されます。

DownloadページにOSを選択するアイコンがあるのでmacOSのApple siliconを選択します。リンクをクリックすると、VSCode-darwin-arm64.zipがダウンロードされます。

ダウンロードディレクトリに「VSCode-darwin-arm64.zip」というファイルがあるのでダブルクリックで解凍してください。

Visual Studio Code.appというファイルが出来るので、それをアプリケーションディレクトリに移動すればインストール完了です。


VS CodeへのC#拡張機能のインストール

VS Codeを起動します。画面左の「Extentions」アイコンをクリックして拡張機能のメニューを呼び出します。

拡張機能検索エリアに「C#」を入力すると、該当する拡張機能がリストアップされます。その中から以下の拡張機能を選択して、それぞれインストールしてください。

これらのプラグインを組み合わせることで、C#の開発がよりスムーズで効率的になり、初心者からプロまで、幅広い開発者にとって非常に便利な環境となります。

  • C# for Visual Studio Code
    • C#での開発をサポートするために基本的な機能(コード補完、デバッグ支援、構文強調表示など)を提供します。
  • C# Dev Kit for Visual Studio Code
    • C# for Visual Studio Codeプラグインをさらに強化するための追加ツールで、特にプロジェクトテンプレートやテスト関連の機能が追加されます。
  • IntelliCode for C# Dev Kit
    • IntelliCode for C# Dev Kitは、AIを活用してコーディングを支援し、よりスマートな開発を実現します。

NuGetのインストール

HomebrewでNuGetをインストールします。ターミナルを開き、以下のコマンドを入力します。

brew update
brew install nuget

インストールが完了したら、nugetコマンドが使用できるようになります。

nugetインストール時のコマンド実行ログです。

(base) xxxxxx@xxxxxx test-pj % brew update
==> Updating Homebrew...
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
cmrc            dwarfs          js-beautify     kea             slackdump
crow            firefly         jsbeautifier    packcc          spoofdpi
==> New Casks
font-lxgw-simxihei         microsoft-openjdk@21       retcon
font-lxgw-simzhisong       neo-network-utility        truetree
font-server-mono           oxygen-xml-developer       winbox
gauntlet                   photostickies              xmenu
==> Outdated Formulae
gcc

You have 1 outdated formula installed.
You can upgrade it with brew upgrade
or list it with brew outdated.
(base) xxxxxx@xxxxxx test-pj % brew install nuget
==> Downloading <https://ghcr.io/v2/homebrew/core/nuget/manifests/6.11.0>
######################################################################### 100.0%
==> Fetching dependencies for nuget: mpdecimal, sqlite, python@3.12 and mono
==> Downloading <https://ghcr.io/v2/homebrew/core/mpdecimal/manifests/4.0.0-1>
==> Installing nuget
==> Pouring nuget--6.11.0.all.bottle.tar.gz
🍺  /opt/homebrew/Cellar/nuget/6.11.0: 5 files, 8.2MB
==> Running `brew cleanup nuget`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
(base) xxxxxx@xxxxxx test-pj % 

NuGetのバージョンを確認します。

以下のコマンドを入力して、NuGetのバージョン情報を確認します。

nuget

以下、nugetコマンド実行時のログです。これで、.NETに関する追加ライブラリーの管理が出来る様になりました。

(base) xxxxxx@xxxxxx test-pj % nuget
NuGet バージョン: 6.11.0.119
使用方法: NuGet <command> [args] [options]
特定のコマンドヘルプを表示するには、'NuGet help <command>' と入力してください。

使用できるコマンド:
...

PostgreSQLのインストール

Dockerコンテナでの構築

今回、PostgreSQLのデータベースは、後述のDocker コンテナで構築しローカル環境とサーバー環境で共通としますので、ここではインストールしません。

通常のmacOSへのインストールよりも、Dockerコンテナの方が楽に構築出来るので、この際チャレンジしてみてください。

macOSにインストールする

Dockerコンテナが難しい方は、ダウンロードサイトからインストーラを入手して、インストールしてください。

PostgreSQL Version 16.4、mac OS Xのリンクをクリックするとダウンロード出来ます。

ダウンロードされた、「postgresql-16.4-1-osx.dmg」をダブルクリックして、インストールしてください。


pgAdmin4のインストール

pgAdminの公式サイトへアクセスし、メニューにあるDownloadリンクへ遷移してください。

DownloadページにOSを選択するアイコンがあるのでmacOSを選択します。、macOS Sonomaは、v7.8以降のバージョンを選択する必要があります。

今回は、最新バージョンであるpgAdmin 4 v8.11を選択します。

ダウンロードディレクトリに「pgadmin4-8.11-arm64.dmg」というファイルがあるのでダブルクリックし、インストールしてください。


サーバー環境の構築

DockerコンテナにC#と.NET SDKをインストールするための手順は以下の通りです。

  • Docker Desktopのインストール
  • Web APIプロジェクトの作成
  • Dockerfileの作成
  • Docker Composeの設定

Docker Desktopのインストール

ASP.NET 8.0とPostgreSQLは、Docker コンテナで構築するので、事前にインストールしておきます。

Docker Desktopのインストールについては、以下の記事で詳細に解説していますので、こちらをご覧下さい。


Web APIプロジェクトの作成

VS Codeを起動しコマンドパレットを表示します。コマンドパレットの検索エリアに「.NET new」と入れると、「.NET: New Project」が表示されるので、選択します。

今回は、ASP.NET Core Empty(Webアプリ開発での一番シンプルな空のテンプレート)を選択します。

次に、プロジェクトを作成するするディレクトリを指定します。プロジェクトディレクトリの親ディレクトリを選択して、「SimpleLibraryApi」の名前でプロジェクトを作成してください。

作成が終わると、以下のディレクトリ構成が生成されます。

/SimpleLibraryApi
├── SimpleLibraryApi
│   ├── Program.cs
│   ├── Properties
│   ├── SimpleLibraryApi.csproj
│   ├── appsettings.Development.json
│   ├── appsettings.json
│   ├── Dockerfile
│   ├── docker-compose.yml
│   ├── bin
│   └── obj
└── SimpleLibraryApi.sln


Web APIプロジェクトの動作確認

Web APIのプロジェクトが正しく動作するか確認します。

Program.csを開いて、右上にある実行ボタンをクリックします。正常に起動すると自動でWebブラウザが開き、「Hello World!」が表示されます。


Dockerfileの作成

プロジェクトのルートディレクトリにあるSimpleLibraryApiディレクトリにDockerfileという名前のファイルを作成し、以下の内容を記述します。

# 1. ベースとなるイメージを指定します。
FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim AS base
WORKDIR /app

# 2. SDKを使用してビルドを行います。
FROM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build
WORKDIR /src
COPY . .
RUN dotnet restore SimpleLibraryApi.csproj
RUN dotnet publish SimpleLibraryApi.csproj -c Release -o /app

# 3. 最終的なランタイムイメージを作成します。
FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim AS final
WORKDIR /app
COPY --from=build /app .

ENTRYPOINT ["dotnet", "SimpleLibraryApi.dll"]

Docker Composeの設定

プロジェクトのルートディレクトリにあるSimpleLibraryApiディレクトリにdocker-compose.ymlという名前のファイルを作成し、以下の内容を記述します。

サーバー環境の場合、Dockerコンテナ内部でwebapiがリッスンするポート番号は8080となりアプリケーション側の設定は無効になりますので注意してください。

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: library_db
      POSTGRES_USER: user
      POSTGRES_PASSWORD: passwd
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data 

  webapi:
    build: .
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "8080:8080"
    depends_on:
      - db
      
volumes:
  postgres_data:

DBの動作確認

PostgreSQLデータベースにアクセスするために、「db」という名前で127.0.0.1にアクセス出来るようにhostsにエントリーポイント追加します。

この設定により、ローカル環境、サーバー環境のどちらでも共通の設定ファイル(appsettings.json)にてPostgreSQLのデータベースにアクセス出来るようになります。

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       db

Dockerコンテナの「db」サービス起動

VS Codeで、「db」サービスを起動します。

docker-compose.ymlを右クリックして、コンテキストメニューを開きます。メニューから「Compose Up – Select Services」を選択します。

画面上部に、起動するサービスの選択画面が表示されるので、「db」のみチェックして、「OK」ボタンをクリックしPostgreSQLのデータベースを起動します。

Executing task: docker compose  -f "SimpleLibraryApi/docker-compose.yml" up -d --build db 

[+] Running 15/1
 ✔ db Pulled                                                                         10.2s 
[+] Running 3/3
 ✔ Network simplelibraryapi_default         Cre...                                    0.0s 
 ✔ Volume "simplelibraryapi_postgres_data"  Created                                   0.0s 
 ✔ Container simplelibraryapi-db-1          Star...                                   0.7s 
 *  Terminal will be reused by tasks, press any key to close it. 

pgAdmin4での確認

Launchpadから、pgAdmin4を起動します。サーバーの追加画面から、以下の設定でデータベースへの接続設定を行います。

Host name/address:db

Port:5432

Username:user(docker-compose.ymlと同じ)

Password:passwd(docker-compose.ymlと同じ)

接続できると、Databasesの下に「library_db」が出来ているのが確認出来ます。


追加パッケージのインストール

今回のWeb APIで必要となるデータベースアクセス関連の実装に必要なパッケージをインストールします。

関連パッケージのインストールは、VS Codeを使ってGUIから行います。以下にその手順を説明します。

  1. プロジェクトをVS Codeで開く:
    • まず、インストールしたいプロジェクトディレクトリをVS Codeで開きます。
  2. NuGet パッケージマネージャーを開く:
    • メニューから表示 > パレットを表示を選択します。
    • コマンドパレットが開いたら、「NuGet」を検索し、NuGet パッケージの管理またはNuGet: Add Packageを選択します。
  3. パッケージを検索してインストール:
    • NuGet パッケージの管理を選択すると、現在のプロジェクトに追加されているパッケージが一覧表示されます。
    • 上部の検索バーにインストールしたいパッケージ名を入力します。
    • 検索結果から該当するパッケージを選択し、インストールするバージョンを選択します。
    • Enterキーを押すと、パッケージがプロジェクトに追加されます。
    • 今回は、以下のパッケージをインストールします。
      • Microsoft.EntityFrameworkCore 8.0.4
      • Microsoft.EntityFrameworkCore.Design 8.0.4
      • Npgsql.EntityFrameworkCore.PostgreSQL 8.0.4
      • Microsoft.AspNetCore.OpenApi 8.0.8
      • Swashbuckle.AspNetCore 6.7.3
  4. csprojファイルの確認:
    • パッケージが正しくインストールされると、プロジェクトのcsprojファイルに該当するパッケージの依存関係が自動的に追加されます。

パッケージインストール後のSimpleLibraryApi.csprojファイルは以下の通りです。

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
  </ItemGroup>


プログラム開発&実行

それでは、いよいよWebAPIの開発に入っていきます。

今回作成・編集するコードは以下の通りです。

  • Bookクラス(データモデル)
  • LibraryContextクラス(データベースコンテキスト)
  • BookRepositoryクラス(リポジトリ)
  • BooksController(コントローラー)
  • Program.cs(エントリーポイント)
  • appsettings.jsonの編集

コードの作成・編集が終わると、以下のディレクトリ構成となります。

※今回の作業に必要なもの以外は一部省略しています。

/SimpleLibraryApi
├── SimpleLibraryApi
│   ├── Models
│   │  └── Book.cs
│   ├── Data
│   │  └── LibraryContext.cs
│   ├── Repositories
│   │  └── BookRepository.cs
│   ├── Controllers
│   │  └── BooksController.cs
│   ├── Program.cs
│   ├── appsettings.json
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── obj
└── SimpleLibraryApi.sln


Bookクラス(データモデル)の作成

Modelsディレクトリを作成します。

Modelsディレクトリには、アプリケーションで使用するデータモデルが格納されます。データモデルは、アプリケーションが扱うデータの構造を定義します。

Bookクラス(データモデル):

Bookクラスは書籍の情報(タイトル、著者、ISBN、発行年など)を表現し、この情報をデータベースに保存したり、APIのレスポンスとして返したりします。

Book.csファイル

namespace SimpleLibraryApi.Models
{
    // Bookクラスは、書籍の情報を表すデータモデルです。
    // ここでは、タイトル、著者、ISBN、発行年を管理します。
    public class Book
    {
        // 書籍の一意の識別子(ID)を管理します。
        public int Id { get; set; }

        // 書籍のタイトルを管理します。
        public string Title { get; set; } = string.Empty;

        // 著者の名前を管理します。
        public string Author { get; set; } = string.Empty;

        // 書籍のISBNコード(国際標準図書番号)を管理します。
        public string ISBN { get; set; } = string.Empty;

        // 書籍が発行された年を管理します。
        public int PublishedYear { get; set; }
    }
}


LibraryContextクラス(データベースコンテキスト)の作成

Dataディレクトリを作成します。

Dataディレクトリには、データベースとのやり取りを管理するクラスが格納されます。このディレクトリは、主にEntity Framework Coreを使用してデータベース操作を行うクラスを含みます。

LibraryContextクラス(データベースコンテキスト):

LibraryContextクラスは、Entity Framework Coreを通じてデータベースに接続し、Bookモデルと対応するデータベーステーブルとのやり取りを管理します。

LibraryContext.csファイル

using Microsoft.EntityFrameworkCore;
using SimpleLibraryApi.Models;

namespace SimpleLibraryApi.Data
{
    // LibraryContextクラスは、データベースとの接続を管理します。
    // DbContextを継承しており、データベース操作を行うための設定を行います。
    public class LibraryContext : DbContext
    {
        // コンストラクタで、DbContextOptionsを使用してデータベース接続設定を行います。
        public LibraryContext(DbContextOptions<LibraryContext> options)
            : base(options)
        {
        }

        // 書籍データを管理するDbSetを定義します。
        // このDbSetを使って、データベース内のBooksテーブルにアクセスします。
        public DbSet<Book> Books { get; set; }
    }
}


BookRepositoryクラス(リポジトリ)の作成

Repositoriesディレクトリを作成します。

Repositoriesディレクトリには、データベースのCRUD(Create, Read, Update, Delete)操作を抽象化するリポジトリクラスが格納されます。このクラスを通じて、データベース操作が行われます。

BookRepositoryクラス(リポジトリ):

BookRepositoryクラスは、Bookデータをデータベースに保存、取得、更新、削除するメソッドを提供します。これにより、コントローラーとデータベースの間に分かりやすい役割分担が生まれます。

BookRepository.csファイル

using SimpleLibraryApi.Data;
using SimpleLibraryApi.Models;
using Microsoft.EntityFrameworkCore;

namespace SimpleLibraryApi.Repositories
{
    // BookRepositoryクラスは、データベースへのアクセスを抽象化します。
    // このクラスを使って、書籍データのCRUD操作(作成、読み取り、更新、削除)を行います。
    public class BookRepository
    {
        private readonly LibraryContext _context;

        // コンストラクタで、データベースコンテキストを受け取ります。
        // これにより、データベースにアクセスできるようになります。
        public BookRepository(LibraryContext context)
        {
            _context = context;
        }

        // すべての書籍を取得するメソッドです。
        public async Task<IEnumerable<Book>> GetAllBooksAsync()
        {
            // データベースからすべての書籍を非同期で取得します。
            return await _context.Books.ToListAsync();
        }

        // 指定したIDに基づいて書籍を取得するメソッドです。
        public async Task<Book?> GetBookByIdAsync(int id)
        {
            // IDで書籍を検索し、見つけた場合はそれを返します。
            return await _context.Books.FindAsync(id);
        }

        // ISBNで書籍を検索するメソッドです。
        public async Task<Book?> GetBookByISBNAsync(string isbn)
        {
            // ISBNで書籍を検索し、見つけた場合はそれを返します。
            return await _context.Books.FirstOrDefaultAsync(b => b.ISBN == isbn);
        }

        // 新しい書籍をデータベースに追加するメソッドです。
        public async Task AddBookAsync(Book book)
        {
            _context.Books.Add(book);  // 書籍をデータベースに追加します。
            await _context.SaveChangesAsync();  // データベースに変更を保存します。
        }

        // 書籍の情報を更新するメソッドです。
        public async Task UpdateBookAsync(Book book)
        {
            _context.Books.Update(book);  // 書籍の情報を更新します。
            await _context.SaveChangesAsync();  // データベースに変更を保存します。
        }

        // 書籍をデータベースから削除するメソッドです。
        public async Task DeleteBookAsync(Book book)
        {
            _context.Books.Remove(book);  // 書籍をデータベースから削除します。
            await _context.SaveChangesAsync();  // データベースに変更を保存します。
        }
    }
}


BooksController(コントローラー)の作成

Controllersディレクトリを作成します。

Controllersディレクトリには、アプリケーションのコントローラークラスが格納されます。コントローラーは、HTTPリクエストを処理し、適切なレスポンスを返す役割を持ちます。

BooksControllerクラス(コントローラー):

Web APIのエンドポイントを定義し、リクエストに対するアクションメソッド(例: GET, POST, PUT, DELETE)を提供します。例えば、BooksControllerクラスには書籍情報を操作するAPIエンドポイントが含まれます。

BookRepository.csファイル

using Microsoft.AspNetCore.Mvc;
using SimpleLibraryApi.Models;
using SimpleLibraryApi.Repositories;

namespace SimpleLibraryApi.Controllers
{
    // BooksControllerクラスは、HTTPリクエストを処理し、クライアントに応答を返します。
    // このコントローラーは、/api/booksエンドポイントに対応しています。
    [ApiController]
    [Route("api/[controller]")]
    public class BooksController : ControllerBase
    {
        private readonly BookRepository _repository;

        // コンストラクタで、BookRepositoryを受け取り、依存性注入を行います。
        public BooksController(BookRepository repository)
        {
            _repository = repository;
        }

        // すべての書籍を取得するGETメソッドです。
        [HttpGet]
        public async Task<IEnumerable<Book>> GetAllBooks()
        {
            // リポジトリを通じてデータベースからすべての書籍を取得します。
            return await _repository.GetAllBooksAsync();
        }

        // 指定されたIDの書籍を取得するGETメソッドです。
        [HttpGet("{id}")]
        public async Task<IActionResult> GetBookById(int id)
        {
            // IDに基づいて書籍を取得します。
            var book = await _repository.GetBookByIdAsync(id);

            if (book == null)
            {
                // 書籍が見つからない場合は404エラーを返します。
                return NotFound();
            }

            // 書籍が見つかった場合は200 OKとともに書籍情報を返します。
            return Ok(book);
        }

        // ISBNで書籍を検索するGETメソッドです。
        [HttpGet("isbn/{isbn}")]
        public async Task<IActionResult> GetBookByISBN(string isbn)
        {
            // ISBNに基づいて書籍を取得します。
            var book = await _repository.GetBookByISBNAsync(isbn);

            if (book == null)
            {
                // 書籍が見つからない場合は404エラーを返します。
                return NotFound();
            }

            // 書籍が見つかった場合は200 OKとともに書籍情報を返します。
            return Ok(book);
        }

        // 新しい書籍を追加するPOSTメソッドです。
        [HttpPost]
        public async Task<IActionResult> AddBook(Book newBook)
        {
            // リポジトリを通じて書籍をデータベースに追加します。
            await _repository.AddBookAsync(newBook);
            // 書籍が正常に追加された場合、201 Createdとともに書籍情報を返します。
            return CreatedAtAction(nameof(GetBookById), new { id = newBook.Id }, newBook);
        }

        // 書籍の情報を更新するPUTメソッドです。
        [HttpPut("{id}")]
        public async Task<IActionResult> UpdateBook(int id, Book updatedBook)
        {
            if (id != updatedBook.Id)
            {
                // IDが一致しない場合は400 Bad Requestを返します。
                return BadRequest();
            }

            // 書籍の情報を更新します。
            await _repository.UpdateBookAsync(updatedBook);
            // 更新が成功した場合、204 No Contentを返します。
            return NoContent();
        }

        // 書籍を削除するDELETEメソッドです。
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteBook(int id)
        {
            // IDに基づいて書籍を取得します。
            var book = await _repository.GetBookByIdAsync(id);

            if (book == null)
            {
                // 書籍が見つからない場合は404エラーを返します。
                return NotFound();
            }

            // 書籍をデータベースから削除します。
            await _repository.DeleteBookAsync(book);
            // 削除が成功した場合、204 No Contentを返します。
            return NoContent();
        }
    }
}


Program.cs(エントリーポイント)でサービスを登録

データベースコンテキストとリポジトリ、コントローラーをサービスとして登録します。

また、Swaggerを使ってAPIのドキュメントとテストが出来るようにします。

Program.csファイル

using Microsoft.EntityFrameworkCore;
using SimpleLibraryApi.Data;
using SimpleLibraryApi.Repositories;

var builder = WebApplication.CreateBuilder(args);

// サービスの登録
// ここでは、必要なサービス(DBコンテキスト、リポジトリ、コントローラーなど)をDIコンテナに登録します。
builder.Services.AddDbContext<LibraryContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

// BookRepositoryをサービスとして登録します。
// これにより、コントローラーで依存性注入が可能になります。
builder.Services.AddScoped<BookRepository>();

// コントローラーを追加します。これでMVCパターンを利用した開発が可能になります。
builder.Services.AddControllers();

// APIのドキュメント生成を行うためのSwaggerを追加します。
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// 開発環境での設定
// 開発中は、Swaggerを利用してAPIのテストが簡単に行えます。
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

// HTTPリクエストをHTTPSにリダイレクトする設定
app.UseHttpsRedirection();

// 認証を行うためのミドルウェア
app.UseAuthorization();

// ルーティング設定
// APIコントローラーへのリクエストを正しいアクションにマップします。
app.MapControllers();

app.Run();  // アプリケーションを起動します。


appsettings.jsonの編集

データベース接続文字列の設定を行います。

appsettings.jsonファイルにデータベース接続文字列を追加します。

appsettings.jsonファイル

{
  // データベース接続のための設定です。
  // Hostにはデータベースサーバーのホスト名を指定し、
  // Databaseには使用するデータベース名、UsernameとPasswordにはログイン情報を指定します。
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Database=library_db;Username=yourusername;Password=yourpassword"
  },
  "Logging": {
    // ロギングのレベル設定です。
    // どの程度の情報をログに記録するかを指定します。
    "LogLevel": {
      "Default": "Information",  // 通常の情報ログを記録
      "Microsoft.AspNetCore": "Warning"  // ASP.NET Coreに関する警告以上のログを記録
    }
  },
  // アプリケーションがアクセスを許可するホストを指定します。
  // "*"はすべてのホストからのアクセスを許可することを意味します。
  "AllowedHosts": "*"
}


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

WebAPIに必要なテーブルをPostgreSQLのデータベースに作成します。

以下のコマンドを実行して、マイグレーションファイルの作成、データベースのマイグレーションを行って下さい。

dotnet ef migrations add InitialCreate
dotnet ef database update

マイグレーションファイルの作成ログです。プロジェクトディレクトリの「Migrations」ディレクトリにcsファイルが作成されます。

(base) xxxxxx@xxxxxx SimpleLibraryApi % dotnet ef migrations add InitialCreate
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
(base) xxxxxx@xxxxxx restapi-aspnet-core % 

データベースのマイグレーション実行時のログです。PostgreSQLのデータベースを確認するとBooksテーブルが作成されていることが確認出来ます。

また、実行時にはPostgreSQLのデータベースを起動しておいてください。起動していないとエラーとなります。

(base) xxxxxx@xxxxxx restapi-aspnet-core % dotnet ef database update
Build started...
Build succeeded.
Npgsql.NpgsqlException (0x80004005): Failed to connect to 127.0.0.1:5432
 ---> System.Net.Sockets.SocketException (61): Connection refused
   at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
   at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
   at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Failed to connect to 127.0.0.1:5432

(base) xxxxxx@xxxxxx restapi-aspnet-core % dotnet ef database update
Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (20ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT EXISTS (
          SELECT 1 FROM pg_catalog.pg_class c
          JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
          WHERE n.nspname='public' AND
                c.relname='__EFMigrationsHistory'
      )
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT EXISTS (
          SELECT 1 FROM pg_catalog.pg_class c
          JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
          WHERE n.nspname='public' AND
                c.relname='__EFMigrationsHistory'
      )
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (6ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE "__EFMigrationsHistory" (
          "MigrationId" character varying(150) NOT NULL,
          "ProductVersion" character varying(32) NOT NULL,
          CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
      );
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT EXISTS (
          SELECT 1 FROM pg_catalog.pg_class c
          JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
          WHERE n.nspname='public' AND
                c.relname='__EFMigrationsHistory'
      )
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT "MigrationId", "ProductVersion"
      FROM "__EFMigrationsHistory"
      ORDER BY "MigrationId";
info: Microsoft.EntityFrameworkCore.Migrations[20402]
      Applying migration '20240901054819_InitialCreate'.
Applying migration '20240901054819_InitialCreate'.
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE "Books" (
          "Id" integer GENERATED BY DEFAULT AS IDENTITY,
          "Title" text NOT NULL,
          "Author" text NOT NULL,
          "ISBN" text NOT NULL,
          "PublishedYear" integer NOT NULL,
          CONSTRAINT "PK_Books" PRIMARY KEY ("Id")
      );
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
      VALUES ('20240901054819_InitialCreate', '8.0.4');
Done.
(base) xxxxxx@xxxxxx restapi-aspnet-core %


ローカル環境での実行

アプリケーションのビルドと実行

以下のコマンドを実行して、WebAPIを起動します。

dotnet run --urls <http://localhost:5000>

Webブラウザでhttp://localhost:5000/api/booksにアクセスしてAPIが正常に動作することを確認します。

Webブラウザでhttp://localhost:5000/swagger/index.htmlにアクセスしてAPIドキュメントとテストが動作することを確認します。


サーバー環境での実行

Dockerイメージのビルドとコンテナの起動

以下のコマンドを実行して、WebAPIを起動します。

docker compose up --build

Webブラウザでhttp://localhost:8080/api/booksにアクセスし、APIが正常に動作することを確認します。

Webブラウザでhttp://localhost:8080/swagger/index.htmlにアクセスしてAPIドキュメントとテストが動作することを確認します。


学習ポイント解説

今回作成したWebAPIのコードをベースに、ASP.NETとC#の学習ポイントを解説します。

解説のポイントは、以下の通りです。

  • HTTPリクエストとレスポンス
  • ルーティング


HTTPリクエストとレスポンス:

HTTPプロトコルを使ったデータのやり取りを解説します。

  • HTTP(HyperText Transfer Protocol)は、インターネット上でデータをやり取りするためのルールです。Web APIはこのHTTPを使ってクライアントとサーバー間でデータを送受信します
  • HTTPリクエストとは、クライアント(たとえばブラウザやスマホアプリ)がサーバーにデータを要求することです。たとえば、「この本の情報を教えて」というリクエストをサーバーに送ります。
  • HTTPレスポンスとは、サーバーがクライアントに返す答えです。たとえば、「この本のタイトルは〇〇です」という情報をクライアントに返します。

ASP.NET CoreでのWeb APIでは、以下のようにHTTPリクエストとレスポンスを処理します。

[HttpGet("{id}")]
public async Task<IActionResult> GetBookById(int id)
{
    var book = await _repository.GetBookByIdAsync(id);

    if (book == null)
    {
        return NotFound(); // 404エラーを返す(リクエストされたデータが見つからない場合)
    }

    return Ok(book); // 200 OKとともにデータを返す
}

このコードでは、クライアントから「特定のIDの本の情報を教えて」というリクエスト(HTTP GET)を受け取り、その情報が見つかればレスポンスとしてデータを返します。見つからなければ「404 Not Found」というエラーを返します。


ルーティング:

APIエンドポイントを作成し、ルーティングの仕組みを解説します。

  • ルーティングとは、クライアントから送られてきたリクエストを、どの処理に対応させるかを決める仕組みです。APIエンドポイントとは、リクエストを受け取るURLのことです。
  • たとえば、/api/booksというエンドポイントを設定すると、このURLにリクエストが送られてきたときにどの処理を実行するかを指定します。

下記のコードでは、/api/booksにアクセスすると、すべての書籍情報が返され、/api/books/{id}にアクセスすると特定のIDに対る書籍情報が返されます。ルーティングを理解することで、どのリクエストがどの処理に対応するかをコントロールできるようになります。

[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    // "/api/books"に対応するエンドポイントを設定します。
    [HttpGet]
    public async Task<IEnumerable<Book>> GetAllBooks()
    {
        // 書籍リストを返す処理
    }

    // "/api/books/{id}"に対応するエンドポイントを設定します。
    [HttpGet("{id}")]
    public async Task<IActionResult> GetBookById(int id)
    {
        // 特定のIDに対応する書籍を返す処理
    }
}


テンプレートアプリ解説

.NET 8.0のWeb APIプロジェクトテンプレートは、Web API開発に必要な基本要素を一通り含んでいます。機能としては、ランダムに天気情報を返却してくるAPIとなります。

テンプレートは、各構成要素が特定の役割を持っています。これらを理解することで、初期設定に時間を取られず、アプリケーションの機能開発に集中することができます。

  • Program.cs
  • appsettings.json
  • Propertiesディレクトリ
【筆者の経験談】
この辺りは、さすがMicrosoftだと感心しました!VisualC++5.0を初めて使った際、テンプレートコードが手取り足取りサポートしてくれる、そんな感じでコーディングを進めることが出来ます。初心者に非常に優しかった事を思い出しますね。


Program.cs

.NET 8.0では、Program.csはプロジェクトのエントリーポイント(最初に実行されるコード)です。このファイルで、アプリケーションの設定、サービスの登録、そしてアプリケーションの実行が行われます。

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();


appsettings.json

appsettings.jsonは、アプリケーションの設定情報をJSON形式で記述するファイルです。データベース接続文字列やロギングの設定、他の構成情報をここに記載します。

{
  // Logging セクションは、アプリケーションのログ出力に関する設定を定義します。
  "Logging": {
    "LogLevel": {
      // LogLevel セクションは、ログの出力レベルを設定します。

      // "Default": "Information" は、アプリケーション全体のデフォルトのログレベルを 
      // Information に設定しています。これにより、Information レベル以上のログ
      // (Information、Warning、Error、Critical)が出力されます。
      "Default": "Information",

      // "Microsoft.AspNetCore": "Warning" は、Microsoft.AspNetCore 名前空間に
      // 関連するログのレベルを Warning に設定しています。これにより、ASP.NET Core
      // フレームワークから出力されるログは Warning レベル以上のもの
      // (Warning、Error、Critical)のみが出力されます。
      "Microsoft.AspNetCore": "Warning"
    }
  },

  // AllowedHosts セクションは、アプリケーションが受け入れるホスト名を設定します。
  // "*" は、どのホスト名でも受け入れることを意味します。
  "AllowedHosts": "*"
}


Propertiesディレクトリ

Propertiesディレクトリには、アプリケーションのプロパティや構成情報が含まれます。特に、アプリケーションがどうビルドされ、デプロイされるかに関連する設定が格納されます。

launchSettings.json: ローカル開発環境での設定を記述したファイルです。例えば、アプリケーションがデバッグモードで起動するときにどのURLを使用するかなどの情報が含まれます。なお、このポート番号は、プロジェクトを生成する度に変更されますので、ご注意ください。

{
  // $schema は、この JSON ファイルのスキーマを指定します。
  // スキーマはファイルの構造やフィールドが正しいかどうかを検証するために使用されます。
  "$schema": "<http://json.schemastore.org/launchsettings.json>",

  // iisSettings セクションは、IIS Express でのアプリケーションの実行設定を定義します。
  "iisSettings": {
    // Windows 認証を無効にしています。
    "windowsAuthentication": false,

    // 匿名認証を有効にしています。
    "anonymousAuthentication": true,

    // IIS Express に関連する設定を指定します。
    "iisExpress": {
      // アプリケーションがホストされる URL を指定します。
      "applicationUrl": "<http://localhost:24278>",

      // HTTPS アクセス用のポート番号を指定します。
      "sslPort": 44371
    }
  },

  // profiles セクションには、アプリケーションを実行するための複数のプロファイルが定義されています。
  // 各プロファイルは、異なる実行設定を持つことができます。
  "profiles": {

    // http プロファイルは、アプリケーションを HTTP で実行する設定です。
    "http": {
      // このプロファイルは、プロジェクト全体として実行されます。
      "commandName": "Project",

      // `dotnet run` コマンド実行時に詳細なメッセージを出力します。
      "dotnetRunMessages": true,

      // アプリケーションの起動時にブラウザを自動的に開きます。
      "launchBrowser": true,

      // ブラウザが開く際にアクセスする初期 URL を指定します(ここでは Swagger UI)。
      "launchUrl": "swagger",

      // アプリケーションがホストされる URL を指定します。
      "applicationUrl": "<http://localhost:5125>",

      // アプリケーションの環境変数を設定します。
      // ここでは開発モード(Development)で実行されます。
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },

    // https プロファイルは、アプリケーションを HTTPS で実行する設定です。
    "https": {
      // このプロファイルは、プロジェクト全体として実行されます。
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",

      // アプリケーションが HTTPS および HTTP でホストされる URL を指定します。
      "applicationUrl": "<https://localhost:7194>;<http://localhost:5125>",

      // 開発モード(Development)で実行されます。
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },

    // IIS Express プロファイルは、IIS Express を使用してアプリケーションを実行する設定です。
    "IIS Express": {
      // このプロファイルは、IIS Express で実行されます。
      "commandName": "IISExpress",

      // アプリケーションの起動時にブラウザを自動的に開きます。
      "launchBrowser": true,

      // ブラウザが開く際にアクセスする初期 URL を指定します(ここでは Swagger UI)。
      "launchUrl": "swagger",

      // 開発モード(Development)で実行されます。
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}


最後に

初心者の方でも、この記事を通じてC#とASP.NETの基本的な理解を得ることができたことを願っています。これをきっかけに、ぜひC#と.NETの世界に一歩踏み出してみてください!

SNSでもご購読できます。

コメントを残す

*


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。