💡

【ASP.NET Core入門#1】Program.csの仕組みとミドルウェアパイプラインを完全理解

に公開

【ASP.NET Core入門#1】Program.csの仕組みとミドルウェアパイプラインを完全理解

はじめに

この記事はYouTube動画「【ASP.NET Core入門#1】Program.csの仕組みとミドルウェアパイプラインを完全理解」の補足記事です。
動画で省略した細かい説明やコードの解説をここにまとめています。

🎬 動画はこちら → https://youtu.be/KP2uOPD0ebA
💻 サンプルコード → https://github.com/program-zunda/introduction_asp/tree/intro/episode-01


ASP.NET Coreとは

ASP.NET CoreはMicrosoftが開発した、クロスプラットフォーム対応のWebアプリケーションフレームワークです。

なぜASP.NET Coreを選ぶのか

1. クロスプラットフォーム

旧来のASP.NET FrameworkはWindowsのみで動作していましたが、ASP.NET CoreはWindows・Mac・Linuxどの環境でも動作します。

2. 高いパフォーマンス

TechEmpower Framework Benchmarks(Round 23 / 2025年2月)によると、ASP.NET Core(.NET 9)のPlaintextテストでのスループットはNode.jsのExpressの約100倍の数値を記録しています。

参考:https://www.techempower.com/benchmarks/


プロジェクトを作成する

ターミナルで以下のコマンドを実行します。

ソリューション作成

dotnet new sln -n ZundaService

ソリューション作成コマンドになります。

プロジェクト作成

dotnet new web -n ZundaNet

プロジェクト作成コマンドになります。
今回はASP.NET Core(Empty)と呼ばれるテンプレートで作成しています。
テンプレートとは、.NETが用意しているものでいくつか種類があります。

Web関連テンプレート一覧

テンプレート名 ショートネーム 主な用途
ASP.NET Core Empty web 最小構成。今回の動画で使用
ASP.NET Core Web API webapi REST API開発の定番
ASP.NET Core API(AOT) webapiaot Web APIのAOT(事前コンパイル)最適化版
ASP.NET Core Web App (MVC) mvc Model-View-Controller構成のWebアプリ
ASP.NET Core Web App webapp / razor Razor Pagesベースのサーバーサイドレンダリング
Blazor Web App blazor .NET 8で登場した統合Blazorモデル
Blazor WebAssembly blazorwasm ブラウザ上でC#を動かすWASMアプリ
ASP.NET Core gRPC Service grpc gRPCサービス向け
Worker Service worker バックグラウンド処理・常駐サービス向け

現在インストールされているテンプレートは以下のコマンドで確認できます。

dotnet new list

テンプレートの使い分け

web vs webapi

webは文字通り何も入っていない空の状態です。
webapiはREST APIを作るための設定(OpenAPI / Swaggerのサポートなど)があらかじめ含まれています。
APIサーバーを作りたい場合はwebapiの方がスムーズに始められます。

# 最小構成(今回使用)
dotnet new web -n MyApp
 
# REST API向け
dotnet new webapi -n MyApi

ソリューションへの追加

dotnet sln add ZundaNet/ZundaNet.csproj

ソリューションに作成したプロジェクトを追加するコマンドになります。
ここまでコマンドで実行してきましたが、IDEからこれらを代用することも可能です。
やり方はIDE次第ですので、今回は割愛させていただきます。

なぜソリューションを作るのか

dotnet new webだけでも動くコードは書けます。
それでもソリューションを作る理由は、後から複数のプロジェクトを追加することを見越しているからです。

本格的なASP.NET Coreのアプリケーションは、1つのプロジェクトだけで完結することはほとんどありません。
たとえば本シリーズの第5回で扱うクリーンアーキテクチャでは、次のように役割ごとにプロジェクトを分けます。

ZundaService.sln
├── ZundaNet/          # エントリポイント・ルーティング
├── ZundaLogic/  # ビジネスロジック
├── ZundaDomain/       # エンティティ・ドメインルール
└── ZundaInfrastructure/ # DB・外部サービスとの接続

このとき、ソリューション(.sln)がこれらのプロジェクトをまとめる「フォルダ」の役割を果たします。
IDEでもソリューション単位でプロジェクトを開くため、最初から作っておく習慣をつけておくとスムーズです。

生成されるファイル構成

ZundaService/
├── ZundaService.sln             # ソリューションファイル
└── ZundaNet/
    ├── Program.cs              # アプリの心臓部
    ├── appsettings.json        # 設定ファイル
    ├── appsettings.Development.json  # 開発環境専用の設定
    └── ZundaNet.csproj  # プロジェクト設定
ファイル 役割
Program.cs アプリ全体の設定・起動処理
appsettings.json DB接続先・ログレベルなどの設定値
*.csproj 使用するライブラリ・.NETバージョンの定義

Program.csを読み解く

生成されたProgram.csは以下のようになっています。

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

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

app.Run();

たった4行ですが、ここにASP.NET Coreの核心が詰まっています。順番に見ていきましょう。

1. builderの生成

var builder = WebApplication.CreateBuilder(args);

WebApplicationBuilderのインスタンスを生成します。
builderはアプリの「設計図」を持つ存在で、以下のものを登録する役割を担います。

  • Services:DIコンテナへの部品登録(詳細は第2回)
  • Configurationappsettings.jsonなどの設定読み込み
  • Logging:ログの出力設定
  • Host:Webサーバー(Kestrel)の設定

2. アプリのビルド

var app = builder.Build();

builderの設定をもとにWebApplicationのインスタンスを生成します。
この時点でDIコンテナが確定し、サービスが解決可能な状態になります。

3. ルーティングの定義

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

/(トップページ)へのGETリクエストに対して、文字列を返す処理を定義しています。
これはMinimal APIと呼ばれる記法です。

メソッド 対応するHTTPメソッド
MapGet GET
MapPost POST
MapPut PUT
MapDelete DELETE

4. アプリの起動

app.Run();

Webサーバー(Kestrel)を起動し、リクエストの受付を開始します。
この行はブロッキング呼び出しのため、アプリが停止するまで処理が戻りません。


ミドルウェアパイプライン

ASP.NET Coreの核心的な概念のひとつです。

ミドルウェアとは

リクエストとレスポンスの間に挟まる処理のことです。
複数のミドルウェアがチェーン状に連なり、リクエストを順番に処理します。

Request → [Logging] → [認証] → [Routing] → Response

ミドルウェアの登録

app.UseHttpsRedirection();  // HTTPSへのリダイレクト
app.UseAuthentication();    // 認証
app.UseAuthorization();     // 認可

独自ミドルウェアを作る(補足)

app.Use()を使うと独自の処理を挟むことができます。

app.Use(async (context, next) =>
{
    // リクエスト処理前
    Console.WriteLine($"Request: {context.Request.Path}");

    await next(context); // 次のミドルウェアへ

    // レスポンス処理後
    Console.WriteLine($"Response: {context.Response.StatusCode}");
});

動かしてみる

dotnet run

起動後、ターミナルに表示されたURL(例:http://localhost:5000)をブラウザで開くと「Hello World!」が表示されます。


まとめ

概念 役割
builder アプリの設計図。Services・Configuration・Loggingを登録
.Build() 設計図からアプリを生成。DIコンテナが確定する
app 実行可能なWebアプリ。MiddlewareとRoutingを設定
.Run() Webサーバーを起動しリクエスト待受を開始
ミドルウェア リクエスト/レスポンスに挟まる処理。登録順が重要

次回予告

第2回では**依存性の注入(DI)**を深掘りします。

  • AddScoped / AddTransient / AddSingletonの違いとライフサイクル
  • Optionsパターンによる型安全な設定取得
  • 標準ILoggerの使い方

🎬 動画:作成中
📝 記事:作成中


参考リンク

Discussion