Open12

🟪 ASP.NET Coreで作るWebアプリケーション

sheeplasheepla

はじめに

業務でASP.NET CoreでWebアプリケーションを開発する機会があったため、備忘録と情報整理のためにこのスクラップにまとめていきます。

対象読者

対象読者は次のような方を想定しています。

  • Webについての基本的な知識と他の言語によるWebアプリケーションの開発経験がある人
  • ASP.NET Coreについてサクっとキャッチアップしたい人
  • C#の基本的な文法を把握している人

なお、.NETやASP.NET Coreについての事前知識がなくても導入できるように都度概念や用語の説明を入れてみたつもりです。

ASP.NET Coreとは

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

https://learn.microsoft.com/ja-jp/aspnet/core/overview?view=aspnetcore-6.0

https://www.youtube.com/watch?v=sHDox4Fx6G0&list=PLdo4fOcmZ0oWunQnm3WnZxJrseIw2zSAk

ASP.NET Coreのいいところ(Pros)

  • クロスプラットフォームであり、応答時間などのパフォーマンスに優れています。あくまでひとつの指標ではありますが、公式ページ で紹介されているTech Empower のベンチマーク結果が参考になります。
  • DIに標準の方法が用意されているため、各コントローラやミドルウェアが疎結合になりテストの容易性を保つことができます。
  • EFCoreを使ってSQL操作を抽象化し、LINQによって動的にデータを操作することができます。
  • 認証機能はMicrosoft.AspNetCore.Identityおよびコード生成ツールを使うことでセキュアなWebアプリケーションを少ない手間で作ることができます。
  • C#のモジュールシステムを使うことでDDDやClean Architectureなどの多層的なレイヤをもった構成を組みやすいため、業務アプリケーションの構築に特に適しているフレームワークのひとつです。「スケールアップしやすく、なおかつそこそこスモールスタートでも作りやすい」のがASP.NET Coreの良さなのだろうと個人的には思います。
  • Visual StudioなどのIDEを使って開発することもできますが、基本的な操作は dotnetコマンドで完結します。VSCodeなどの一般的なエディタを使っての開発も十分にサポートされています。
  • .NET SDKといくつかのツールチェインをインストール(もしくはVisual Studioをインストール)してテンプレートからプロジェクトを作成することで開発環境が整うため、環境構築は比較的容易な部類だと思います。

ASP.NET Coreのつらいところ(Cons)

  • 一般的なWebに関する知識だけではなくフレームワークや周辺ツールチェイン固有の覚えるべきことが多いため学習コストが高く感じられるかもしれません。
  • ASP.NET Coreのカバーする機能が非常に広く、プロジェクトの初期テンプレートもいろいろな種類があるため、キャッチアップする際にフレームワークの全体感を掴みにくいという問題があります。(以下にまとめています。)

ASP.NET Coreの関連技術や用語など

  • コントローラ: ASP.NET Coreにおける「コントローラ」とは、HTTPリクエストを処理しレスポンスを生成する一連の処理をハンドリングするためのクラスを表す。一般には、API用のコントローラを作るには ControllerBase を継承し、ビューを返すコントローラを作るには Controller を継承する。
  • Razor View: MVCで使われるテンプレートエンジン。HTMLにC#のコードを埋め込む形で動的なビューをサーバーサイドで作成できる。
  • Blazor Server: サーバー側でUI処理を行い、SignalRでクライアントとリアルタイム通信するSPAモデル。
  • Blazor WebAssembly: ブラウザ上でC#コードをWebAssemblyとして実行するクライアントサイドSPAモデル。
  • SignalR: Websocketによるリアルタイム通信を簡単に実装するためのライブラリ。
  • ASP.NET Core Identity: ユーザー認証や権限管理をサポートする認証フレームワーク。
  • Entity Framework Core (EF Core): .NET向けのフル機能のORM(Object-Relational Mapper)。O/Rマッピングだけではなく、差分抽出やマイグレーション機能を備えており、LINQにより型安全性を維持したまま動的にクエリを構築することができる。
  • ASP.NET Core Code Generator: コントローラーやビューのテンプレートをモデルから自動生成(Scaffold)することができるツール。
  • Microsoft.Extensions.Logging (ILogger): ロギングを統一的に扱うためのインタフェース。ログ出力の詳細を抽象化し、コンソールやファイルなどに柔軟に出力先を切り替えることができる。
  • Microsoft.Extensions.Configuration (IConfiguration): 設定情報の読み込みを統一的に扱うためのインターフェース。
  • Microsoft.Extensions.DependencyInjection: 依存性注入(DI: Dependency Injection)を行うための標準機能を提供するライブラリ。ASP.NET Coreでは、フレームワークが自動的に依存関係を解決しインスタンスを注入してくれるため、アプリケーション全体を疎結合でテストしやすい設計にすることができる。

ASP.NET Coreのプロジェクトテンプレート

ASP.NET Coreには数多くのテンプレートが用意されています。
公式ドキュメントにはそれぞれのテンプレートからアプリケーションを構築するための手順が載っていますが、
全体観が少し分かりにくいため整理すると次のようになります。

目的 テンプレート名 説明
APIのみ webapi Web API用のテンプレート。コントローラ + ルーティングのみを提供する。
MVC Webアプリ mvc コントローラ+ビューでサーバーサイドレンダリングするフル機能のWebアプリ。
Razor Pages Webアプリ webapp ページ単位で作るシンプルなWebアプリ。
Blazor Serverアプリ blazorserver サーバー上でレンダリングしSignalRで双方向通信ができるフルスタックWebアプリケーション。
Blazor WebAssemblyアプリ blazorwasm ブラウザ上で動作するWebAssemblyアプリケーション。
バックグラウンドサービス worker WindowsサービスやLinuxデーモンとして動作可能なバックグラウンドサービス。
gRPCサービス grpc 高速で型安全なRPCサービス。

なお、テンプレートの一覧は dotnet new list コマンドで確認することができます。

ReactやVueなどで作成したSPAフロントエンドを載せる前提の場合は、Web APIテンプレートを使うことができますが、
管理画面のビューやコントローラをコードジェネレータによって自動生成して手早く作りながら、サーバーサイドのロジックに集中したい場合はMVCテンプレートを使うと良いでしょう。MVCからAPI用のコントローラを追加して段階的に「ASP.NET CoreによるREST APIサーバー + 最低限の管理画面」+「一般ユーザーが触る部分はReactによるSPA」といった構成に段階的に移行することもできます。

Web APIテンプレートからプロジェクトを作成すると api.MapGet("weatherforecast", () => { ... }) という記述が出てきます。これは Minimal API というものです。これにより、コントローラクラスを作らずに、HTTPのハンドリング処理を直接書くことができます。
コードの記述がシンプルで済むため、小規模なAPIないしはマイクロサービスを作る場合に活用すると良いでしょう。
一方で、APIの規模が大きくなってきた場合はコントローラクラスを作った方がルーティングをまとめたり責務を分担するのがやりやすいため最初からコントローラクラスを書いた方が楽になる場合も多いかもしれません。

また、C#を基軸にフルスタックなアプリケーションを構築したい場合はBlazorの導入を検討します。

MVCプロジェクトの構造

dotnet new mvc を使って作成したプロジェクトの構造はこのようになっています。

├── appsettings.Development.json ─ 開発環境用の設定ファイル(データベース接続やAPIキーなど環境依存の設定を書く)
├── appsettings.json ─ 共通のアプリケーション設定ファイル(全環境で使用する設定を書く)
├── AspNetCoreTutorial.csproj ─ プロジェクトファイル。依存関係やビルド設定を管理
├── Controllers ─ MVCのコントローラを格納するディレクトリ
│   └── HomeController.cs ─ Home関連の処理(アクションメソッド)を定義するコントローラ
├── Models ─ データモデルやViewModelを格納するディレクトリ
│   └── ErrorViewModel.cs ─ エラー表示用のViewModel
├── obj ─ ビルド中間ファイルが置かれるディレクトリ
├── Program.cs ─ プログラムのエントリーポイント アプリケーション全体の構成や起動処理を定義
├── Properties ─ プロジェクトのプロパティ関連ファイルを格納
│   └── launchSettings.json ─ ローカル実行時の環境設定(URLやプロファイルなど)
├── Views ─ MVCのViewを格納するディレクトリ
│   ├── _ViewImports.cshtml ─ Viewで共通して使う名前空間やTagHelperの指定
│   ├── _ViewStart.cshtml ─ 全Viewで共通のレイアウト指定など初期処理
│   ├── Home ─ HomeControllerに対応するViewを格納
│   │   ├── Index.cshtml ─ HomeControllerのIndexアクション用の画面
│   │   └── Privacy.cshtml ─ HomeControllerのPrivacyアクション用の画面
│   └── Shared ─ 複数Viewで共通して使うViewを格納
│       ├── _Layout.cshtml ─ ページ全体の共通レイアウト(ヘッダー・フッターなど)
│       ├── _Layout.cshtml.css ─ Layout専用のスタイルシート
│       ├── _ValidationScriptsPartial.cshtml ─ バリデーション用のJavaScriptを読み込む部分View
│       └── Error.cshtml ─ エラー画面用View
└── wwwroot ─ 静的ファイル(CSS、JS、画像など)を格納するディレクトリ

この記事の構成(予定)

基本的なCRUDと認証機能を備えた小規模なアプリケーションの構築を目標にします。

ASP.NET Coreの基本機能の概要を掴むために、まずはフル機能の MVC テンプレートから構築を始めます。

次にアプリケーションにREST APIサーバーとしての機能を追加し、
ViteとReactで作成したSPAのフロントエンドを載せて本格的なアプリケーションに拡張していきます。

全体のアーキテクチャはDDDライクな構成にします。ただし、アーキテクチャの議論には深入りしません。

簡易的なアプリケーションのため、データベースは SQLite を採用します。

作成するアプリケーション(構想)

最小限のCRUDと認証機能の概要を掴む題材として「ミニ日報アプリ」を作っていきます。(まだ未作成です。)

  • ログイン
  • ログアウト
  • パスワードの変更
  • ユーザーの管理
  • 日報の作成・更新・削除
  • 日報のCSVインポート/CSVエクスポート
sheeplasheepla

データベースへのアクセス

モデル駆動とクエリ駆動

EF Coreの導入

Microsoft.EntityFrameworkCore (EF Core) はO/Rマッピングやマイグレーション・LINQとの統合などの機能を備えた、.NETで動作するフル機能のORMです。

https://github.com/dotnet/efcore

まずは、EF Coreをインストールします。

dotnet tool install  -g dotnet-ef

dotnet ef を叩いてユニコーンくんが出てくればOKです。カッコいいですね!🦄

$  dotnet ef
dotnet ef

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

Entity Framework Core .NET Command-line Tools 9.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.

プロジェクトへの追加

TODO

モデルの作成

データベースに格納するためのデータのモデルを定義していきます。

TODO

DbContextの作成

DbContext を継承したクラスを定義します。
これは、EF CoreにおいてDBのセッション管理とモデルやリレーションの定義を行うための基本単位となるクラスです。
DbContextの中には、それぞれのテーブルに対応する DbSet<T> やカラム制約・リレーションの詳細設定などを書いていきます。

基本的には1アプリケーションにつきDbContextは1つ作れば事足りることが多いですが、複数のデータベースに問い合わせる必要がある場合やドメインの責務を分離するために複数のDbContextを用意する場合もあります。
分割する基準としては、1つの作業単位(Unit of Work)すなわちトランザクションの境界やライフサイクルの境界として考えると理解しやすいと思います。

TODO

マイグレーションを行う

EF Coreでは、モデルの変更差分をデータベースに反映させることを一般にマイグレーションといいます。

# 「InitialCreate」という名前で最初のマイグレーションファイルを作成し変更差分を記録する
dotnet ef migrasions add InitialCreate

# 現在のマイグレーション差分の一覧を確認する
dotnet ef migrations list

# 差分をデータベースに適用する
dotnet ef database update

マイグレーションしながら進める際の開発サイクル

EF Coreを使ってマイグレーションをしながら進める際の開発サイクルとしては、概ね次のようになると思います。

  • 開発用DBおよびテスト用DBやCI/CDパイプラインの構築などの事前準備
  • 開発
    • DbContextやモデルなどの変更
    • 差分の記録とマイグレーションファイルの作成(dotnet ef migrations add "【マイグレーション名】")
    • 開発環境のデータベースへ変更差分を適用 (dotnet ef database update)
    • 動作確認
    • マイグレーションファイルを含めてGitにコミット
  • コードレビュー等々
  • テスト環境や本番環境への適用 (dotnet ef database update --context AppDbContext --connection "【接続文字列】")

なお、dotnet ef migrations add "【マイグレーション名】" を実行するとマイグレーション用の差分ファイルが Migrations ディレクトリ配下に積み上がっていきますが、ソースファイルと一緒にそれらのファイルごとGitで管理するのが一般的です。
マイグレーションを行うとデータベースの状態が大きく変わってしまうため、必ず開発用・検証用のDBを建てて差分を確認するなどして切り戻しや再構築ができるようにしておきましょう。

sheeplasheepla

認証機能を実装する(ASP.NET Core Identity)

ASP.NET Core Idnetity は、ASP.NET Coreに組み込まれた認証・認可・ユーザー管理のためのフレームワークです。

分類 主な機能
認証 (Authentication/AuthN) Cookieや外部プロバイダー(Google, Facebook, Microsoft, Twitterなど)でのログイン
認可 (Authorization/AuthZ) ロールベース・クレームベースのアクセス制御
ユーザー管理 ユーザー作成、削除、更新、パスワード変更、ロックアウト
セキュリティ パスワードハッシュ化、2要素認証、メール確認、ロックアウトポリシー
データ永続化 Entity Framework Coreを使ってユーザー情報やロールなどをRDBMSに保存

https://learn.microsoft.com/ja-jp/aspnet/core/security/authentication/identity?view=aspnetcore-9.0

認証・認可・ユーザー管理等に関わる複雑でセキュリティ的に注意の必要な処理を一貫して任せられるため、セキュアなWebアプリケーションを比較的少ない手間で作成することができます。
また、コードジェネレータを使ってログイン用のRazorページを自動生成できるのも便利です。

パッケージの追加

dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI

ユーザーアカウントを表すモデルの作成とEFCoreによるマイグレーション

まず、ユーザーアカウントを表すモデルを追加します。

// Models/UserAccountModel.cs
using Microsoft.AspNetCore.Identity;

public class UserAccount : IdentityUser
{
    // 追加したいフィールドがあればここに記述
}

次に、IdentityDbContext 基底としたDbContextを定義します。

// Infrastructure/AppDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

public class AppDbContext : IdentityDbContext<UserAccount>
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }
}

次に、appsettings.jsonに接続文字列を追加して Program.cs で EF CoreとASP.NET Core Identityをセットアップします。

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=ApplicationData/app.db"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
// Program.cs
ususing Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddControllers();
builder.Services.AddOpenApi();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

// EFCore
builder.Services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlite(connectionString);
});

// Identity
builder.Services.AddDefaultIdentity<UserAccount>(options =>
{
    options.SignIn.RequireConfirmedAccount = false;
})
.AddEntityFrameworkStores<AppDbContext>();


var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseRouting();
app.MapControllers();

app.UseAuthorization();

app.MapStaticAssets();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}")
    .WithStaticAssets();
app.MapRazorPages();

app.Run();

マイグレーションを行うと、ASP.NET Core Identity用のテーブルが追加されていることが分かります。

dotnet ef migrations add AddIdentity
dotnet ef database update

▼SQLiteでマイグレーションした結果

https://gist.github.com/sheepla/6facd13b6cef009cebe962e5da978c76

ログインページ等のRazor Pagesの自動生成

ASP.NET Core Code Generatorを使ってログイン・アカウント登録などが行えるRazor Pagesを生成することができます。

https://learn.microsoft.com/ja-jp/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-9.0

dotnet aspnet-codegenerator identity -dc AppDbContext --files "Account.Register;Account.Manage.Index"

実行すると、【プロジェクトルート】/Areas/Identity/ ディレクトリ配下にRazor Pages (*.cshtml, *.cshtml.cs)が生成されます。

また、Razor Pagesを使うために Program.csapp.MapRazorPages();を追加しておきましょう。

アプリケーションを起動して http://localhost:【ポート】/Identity/Account/Login にアクセスするとログインページが表示されるはずです。

/Identity/Account/Loginにアクセスした結果

「Register as a new User」のリンクまたは http://localhost:【ポート】/Identity/Account/Register からRegisterページを開き適当なユーザーを登録してDBの中身を確認してみると、AspNetUsersテーブルにユーザー情報が格納されていることがわかります。(パスワードは当然ハッシュ化されています。)
再びログインページに戻ってそのユーザーでログインできればOKです。

$ sqlite3 ApplicationUser/app.db
sqlite> SELECT * FROM AspNetUsers
   ...> ;
7766d925-353c-4f80-980f-d2ee9133f2fc|0|33e92110-673f-4bb6-b203-11b60a6f4e42|test@example.com|0|1||TEST@EXAMPLE.COM|TEST@EXAMPLE.COM|AQAAAAIAAYagAAAAEBMpGO39tYkAa5Mj5DjyY4gG/OxtTsCCBKEWn4UAStgA2LR9JmdPfPf2V6Es2W0kog==||0|DUS66CDIE7QZQXO4RPWVNGKLIANY7YBY|0|test@example.com

コントローラにアクセス制御を付与する

コントローラにアクセス制御を付与するのは簡単で、コントローラとなるクラスに[Authorize] 属性を付与するだけで実現できます。
これによりログインしたユーザーのみがページにアクセスすることができます。

また、特定のロールのユーザーにのみアクセスを制限したい場合は [Authorize(Roles = "Admin")] のように指定します。複数のロールを許可する場合は [Authorize(Roles = "Admin,Manager")] のようにRolesの文字列値をカンマで区切ります。
ただし、事前にAspNetRolesテーブルでAdmin Manager などのロールが定義されており、ユーザーにそのロールが付与されている必要があります。

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using AspNetCoreIdentityTutorial.Models;
using Microsoft.AspNetCore.Authorization;

[Authorize]
public class HomeController : Controller
{
    // ...
}
sheeplasheepla

REST API機能の追加

MVC用のコントローラとAPI用のコントローラの違い

ASP.NET CoreにおけるコントローラはMVC用のものとAPI用のものでいろいろな違いがあります。(初めて触ったときにこのあたりを混同してしまっていたので説明しておきます…。)

項目 MVC用コントローラ API用コントローラ
基底クラス Controller が一般的 ControllerBaseが一般的
属性 [ApiController] 属性を付与
Razor View サポート ✅ (View(), PartialView())
JSON / XML の応答 可能だがやや冗長 (return Json(obj);) ✅ デフォルト
TempData / ViewBag ✅ 利用可
モデルバリデーション ModelState.IsValid を手動チェック [ApiController] 属性で自動的に400 BadRequestを返す
返却値の型 IActionResultが一般的 ActionResult<T> が一般的

API用のコントローラは Controller ではなく ControllerBase を継承するのが一般的です。返却値の型は、IActionResult ではなく ActionResult<T> を使います。モデルの自動バリデーションやレスポンスのJSON/XMLシリアライズがデフォルトで使えるようになっており、一般的なWeb APIの用途に最適化されています。

実際のコードは次のようになります。

MVC用のコントローラ

public class HomeController : Controller
{
    public IActionResult Index()
    {
        // Razor ビューを返す
        return View();
    }

    [HttpPost]
    public IActionResult SubmitForm(UserModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
        // データ処理
        return RedirectToAction("Success");
    }
}

API用のコントローラ

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet("{id}")]
    public ActionResult<UserDto> GetUser(int id)
    {
        var user = UserRepository.Find(id);
        if (user == null)
        {
            return NotFound();
        }
        return user; // 自動で JSON にシリアライズ
    }

    [HttpPost]
    public ActionResult<UserDto> Create(UserDto user)
    {
        if (user.Name == null)
        {
            return BadRequest();
        }
        var created = UserRepository.Add(user);
        return CreatedAtAction(nameof(GetUser), new { id = created.Id }, created);
    }
}

API用のコントローラの追加

TODO

OpenAPIドキュメントとScalarページの生成

OpenAPIドキュメントのUIとしては Swagger UI が使われることが多いですが、そのモダンな代替としてScalarを使うのが便利です。

https://guides.scalar.com/scalar/scalar-api-references/integrations/net-aspnet-core

Nugetパッケージ Scalar.AspNetCoreMicrosoft.AspNetCore.OpenApi を追加します。

dotnet add package Microsoft.AspNetCore.OpenApi
dotnet add package Scalar.AspNetCore

Program.csでOpenAPIサービスを登録し、OpenAPIとScalarドキュメントのルーティングマップを追加します。

// Program.cs
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddControllers(); // コントローラをサービスに追加
builder.Services.AddOpenApi(); // OpenAPI のメタデータを生成するサービスを追加
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi(); // OpenAPI仕様を提供
    app.MapScalarApiReference(); // ScalarのUIを提供
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseRouting();
app.MapControllers(); // コントローラのルーティングマップを追加
app.UseAuthorization();
app.MapStaticAssets();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}")
    .WithStaticAssets();

app.Run();

dotnet run でアプリケーションを起動します。ブラウザでhttp://localhost:【ポート】/scalarにアクセスしてScalarドキュメントが表示されればOKです。

JWTベースのトークン認証を実装する

TODO

sheeplasheepla

Reactフロントエンドとの連携

APIサーバーとして拡張したASP.NET Coreアプリケーションをを土台にしてReactを使ったSPAフロントエンドを作っていきます。
ただしフロントエンドの詳細は割愛し、バックエンドとの連携部分についてのみ説明します。

メモ: .NETにはASP.NET Core + React (dotnet new react)というテンプレートが用意されていますが、 これはcreate-react-app ベースになっています。
現時点では、新規プロジェクトではVite (もしくはNext.js等)を使うのが無難と思われます。

Create React App の非推奨化 - ja.react.dev

Vite+Reactによるプロジェクトの作成

Vite を使ってReactのテンプレートからプロジェクトを作成します。パッケージマネージャは pnpmを使うことにします。

npm install -g pnpm
pnpm create vite@latest

Frameworkは「React」、Variantは「TypeScript+SWC」を選択します。

◇  Project name:
│  【プロジェクト名】
│
◇  Select a framework:
│  React
│
◇  Select a variant:
│  TypeScript + SWC
│
◇  Scaffolding project in *****...
│
└  Done. Now run:

  cd 【プロジェクト名】
  pnpm install
  pnpm run dev

OpenAPIドキュメントからTypeScriptのクライアントコードを自動生成する

Orvalというツールを使うと、OpenAPIドキュメントからTypeScriptのクライアントコードを自動生成することができます。
これにより、C#で定義したモデル(DTO)→OpenAPI→TypeScriptに型情報を引き継ぐことができ便利です。

基本的なfetch APIクライアントの生成ができるほか、React Query (TanStack Queyr)用のクライアントの生成にも対応しているため、非同期状態管理ができるクライアントをAPI主導でシンプルに実装することができます。

https://orval.dev/

TODO

SPAアプリケーションをASP.NET Coreアプリケーションからサーブする

sheeplasheepla

ビルドとデプロイ

.NETのビルドオプション

Dockerを使ったデプロイ

sheeplasheepla

バックグラウンドジョブを統合的に管理する(Hangfire)

長時間稼働させる必要のあるシステムでは、メールの定期送信、外部API連携、データ集計やレポート生成などのバックグラウンドでなんらかのジョブ動作させたいといった要件が出てくると思います。
こうした処理にはWebリクエストの同期処理に含めるとレスポンスが遅くなりユーザー体験が悪化してしまうため、当然ながら非同期に実行する必要があります。しかし、cronやタスクスケジューラなどで素朴に実装すると処理の依存関係や実行状態の管理が難しくなります。また、外部のミドルウェアやサービスを使うこともできますがシステム全体が大掛かりになってしまう懸念もあります。

そういった場合には Hangfire というライブラリを使うのがおすすめです。

HangfireはDIを使ってバックグラウンド処理をサービスとして登録することで依存関係のあるいろいろなバックグラウンド処理をASP.NET Coreのアプリケーションに簡単に統合することができます。
また、HangfireにはWebベースのダッシュボード機能やジョブ履歴のDBへの永続化機能も備えており、ジョブが正常に動いているかどうかを簡単に追跡することができるため、不具合の切り分けの手助けになり運用者にも優しいライブラリだと言えます。

https://www.hangfire.io/

sheeplasheepla

参考になる書籍

🟨 独習ASP.NET Core: 言わずと知れた「独習」シリーズのASP.NET Coreの解説書です。基本的にはMVCをベースに説明しており現場レベルですぐに使える知見がまとまっています。

https://www.shoeisha.co.jp/book/detail/9784798180557

🟦 Architecting ASP.NET Core Application: Packt Pubから出ている洋書であり、エンタープライズシステムに求められるアーキテクチャやデザインパターンについて詳しく解説してある本です。いい本なので和訳書が出てほしいな…。

https://www.packtpub.com/en-us/product/architecting-aspnet-core-applications-9781805129301

sheeplasheepla

設定の読み込み(IConfiguration)

.NETでは、設定ファイル・コマンドライン引数・環境変数などのいろいろなソースから読み取るための設定を統合的に扱うためのインタフェースとして IConfigurationが用意されています。

https://learn.microsoft.com/ja-jp/dotnet/core/extensions/configuration

Microsoft Docsに掲載されているこの図がイメージしやすいです。

カスタム設定ファイルを読み込む

TODO

sheeplasheepla

CSVインポート/エクスポート機能を実装する

.NETでCSVを処理するには CsvHelper というライブラリを使うのが一般的です。メモリストリームを作成してそれに読み書きを行うことでメモリ上でCSVのレコードを処理することができます。

https://joshclose.github.io/CsvHelper/

TODO