コントローラベースのWeb APIプロジェクトを作成する
まずは、.NET 6以前から利用可能であったコントローラベースのWeb APIの既定のアプリケーションを作成し、その内容を見ていきます。Minimal APIアプリケーションについては、次回(第9回)で紹介します。
プロジェクトの作成
本連載では、プロジェクト群を格納するフォルダをcz_aspdotnetとしていますので、作成していない方は、ここで作成しておいてください。ターミナルを開き、このフォルダに移動して、以下のコマンドでプロジェクトを作成します。
% dotnet new webapi -o WebApiSample --no-https -f net7.0
ここで使われているdotnetコマンドについては、本連載の第2回で紹介していますので、そちらを参照してください。今回は、プロジェクトの名称はWebApiSampleとし、プロジェクトのテンプレートにwebapiを指定しました。dotnet new --listコマンドで表示できるテンプレートの一覧を見ると、「webapi」は「ASP.NET Core Web API」に相当し、言語はC#またはF#で、タグに「Web/WebAPI」が指定されていることがわかります。また、テンプレートオプションを2個指定しています。「--no-https」はHTTPS接続を使用しないことを、「-f net7.0」はターゲットのフレームワークのバージョンを7.0にするという指定です(.NET 7が最新の環境では、指定は省略できます)。
ビルドと実行
WebApiSampleフォルダに新しいプロジェクトが作成されますので、Visual Studio Code(VSCode)のコマンドであるcodeで、このフォルダに移動しておきます。
% code -r WebApiSample
[NOTE]VSCodeの設定
macOSでcodeコマンドを有効化する方法、C#の実行環境のインストール、ビルドとデバッグに必要なアセットのプロジェクトへの追加については、本連載の第2回を参照してください。
[NOTE].NET 6/.NET 7環境が混在している場合
上記のNOTEのように、本稿はプロジェクトを.NET 7をターゲットとして作成しています。ただし.NET 6はLTS(長期サポートバージョン)であり、.NET 6/.NET 7環境が混在している環境で、あえてターゲットを.NET 6とする場合もあるかと思います。このような環境では、以降のdotnet watchコマンドの実行で「Could not load file or assembly 'System.Runtime, Version=7.0.0.0,…」といったエラーが発生することがあります。これは、dotnetコマンドが最新の.NETを使おうとするためなので、.NET 6を使うためにはプロジェクトのルートにglobal.jsonファイルを、以下の内容で設置しておいてください。
{ "sdk": { "version": "6.0.403" } }
なお、versionキーに指定する値は、dotnet --infoコマンドの実行で確認できます。
% dotnet --info .NET SDK: Version: 7.0.100 Commit: e12b7af219 ランタイム環境: …略… .NET SDKs installed: 3.1.415 [/usr/local/share/dotnet/sdk] 6.0.100 [/usr/local/share/dotnet/sdk] 6.0.403 [/usr/local/share/dotnet/sdk] .NET 6の新しいバージョンを指定 7.0.100 [/usr/local/share/dotnet/sdk] …略…
以降、コマンドの操作は基本的にVSCodeのターミナル上で行っていきます。必要に応じてVSCodeのエクスプローラーを利用するとファイルのコピーなどに便利です。
作成したプロジェクトは、dotnet watchコマンドで直ちに実行できます。Web APIではSwaggerと連携するようになっているので、デフォルトブラウザが起動しSwagger UIによるページが表示されます(図3)。このページに表示されているURL(http://localhost:5288/swagger/v1/swagger.json)は、既述のOASを確認するためのリンクです。
% dotnet watch dotnet watch 🔥 Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload. 💡 Press "Ctrl + R" to restart. dotnet watch 🔧 Building... …略…
Swagger UIによるページではAPIの仕様の確認のほかに検証も可能なので、図3のページで既定で用意されているAPIを呼び出してみましょう。図3の[GET]をクリックします。するとリクエストパラメータを入力できるように展開されますが、このAPIはパラメータが不要なのでそのまま[Try it out]をクリックします。すると[Execute]と表示されたボタンが現れますので、クリックしてAPI呼び出しを実行します。Responsesの「Server response」欄に、図4のように気象情報のJSONデータが表示されれば成功です。
この画面には、リクエスト発行のcurlコマンド、URLも表示されますから、別の手段でAPIを検証する際に利用することができます。
[NOTE]Swagger UIページの自動表示
dotnet watchコマンドの実行では、自動的にWebブラウザが起動してSwagger UIのページが表示されます。これは、後述するようにProgram.csファイルにてSwagger UIを有効化するコードが記述されているからですが、このほかにProperties/launchSettings.jsonファイルの★に、Webブラウザ起動とその後に開くURLとしてSwaggerが指定されているという理由もあります。なお、dotnet runコマンドではWebブラウザが起動しないので、この設定は無視されます。Swagger UIのページを開きたければ、明示的にパスを指定する必要があります。
"profiles": { "WebApiSample": { …略… "launchBrowser": true, "launchUrl": "swagger", ★ "applicationUrl": "http://localhost:5288", …略…
プロジェクトの構成とファイル
プロジェクトは、Controllers、Propertiesなどのフォルダと、WeatherForecast.cs、Program.csなどのファイルによって構成されます。コントローラベースであるので、コントローラのファイルがControllersフォルダに置かれます。Propertiesフォルダには、上記の通りアプリケーションの起動に関するlaunchSettings.jsonファイルが置かれます。この構成に、必要に応じてモデルのファイルを置くModelsフォルダなどを追加していくことになります。ただし、既定のモデルのためのWeatherForecast.csファイルは、Modelsフォルダでなくプロジェクトのルートに置かれています。
コントローラを確認する
コントローラファイルについて、具体的に見てみます。
using Microsoft.AspNetCore.Mvc; (1) namespace WebApiSample.Controllers; // Web APIのコントローラクラスとする [ApiController] (2) // コントローラの既定のルートは「コントローラ名」とする [Route("[controller]")] (3) public class WeatherForecastController : ControllerBase (4) { // 気象情報の概要 private static readonly string[] Summaries = new[] (5) { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; // ロガーオブジェクト private readonly ILogger<WeatherForecastController> _logger; (6) // ロガーを受け取るコンストラクタ public WeatherForecastController(ILogger<WeatherForecastController> logger) (7) { _logger = logger; } // HTTP GETのURLパターン省略時(コントローラ名のみのとき)に呼ばれるメソッド [HttpGet(Name = "GetWeatherForecast")] (8) // WeatherForecastのイテレータを返す public IEnumerable<WeatherForecast> Get() (9) { // 気象情報をランダムに5個作成し、配列として返す return Enumerable.Range(1, 5).Select(index => new WeatherForecast (10) { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); (11) } }
基本的には(1)でMicrosoft.AspNetCore.Mvcを参照しているように、MVCと似たような形になっています。例えば(6)(7)のようにコンストラクタがロガーオブジェクトを受け取ったり、リクエストURLに対応するメソッドがそれぞれ定義される点です(第5回を参照)。また、(10)(11)の気象情報の概要の配列、気象情報を返す処理はBlazor Serverの回で扱ったものです(第7回を参照)。ですので、以降はWeb APIの動作に絞って解説します。
(2)は、続けて宣言するクラスがWeb APIのためのコントローラであることを示す属性です。MVCにおいては、Controller属性が記述されます(省略される場合もあります)。
(3)は、属性ルーティングで使用するコントローラまたはアクションのURLパターンの指定です。属性ルーティングとは、規則ベースのルーティングに対する方式で、属性によってコントローラやメソッドごとのルーティングルールを記述する方式です。この場合の[controller]はコントローラ名を意味するので、コントローラ既定のURLパスのパターンは「/WeatherForecast」となります。
(4)では、コントローラクラスが定義されます。MVCではControllerが基底クラスでしたが、ここではさらに基本的なControllerBaseが使用されます。
(8)は、続くメソッドがHTTP GETによるリクエストに対応するものであることを示す属性です。パターンが指定されていないので、リクエストURLは、コントローラで指定された/WeatherForecast」となります。引数のnameは、エンドポイントと引数nameの値"GetWeatherForecast"をOASのoperationId要素(APIごとに割り当てる一意的に識別可能な文字列)としてひも付けるためです。
(9)はAPIのメソッドの定義であり、WeatherForecast型のイテレータを返すものであることを宣言しています。Web APIでは、メソッドが返すデータが直接レスポンスとなりますが、MVCではIActionResult型かTask<IActionResult>を返しました。
Program.csを確認する
Program.csは、アプリケーションの基点となるファイルです。
// ビルダーオブジェクトの生成と、コントローラとSwaggerサポートの追加 var builder = WebApplication.CreateBuilder(args); (1) builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // アプリケーションオブジェクトの生成と、Swaggerサポートの有効化 var app = builder.Build(); (2) if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // 認証と属性ルーティングを有効化してアプリケーションを起動する app.UseAuthorization(); (3) app.MapControllers(); (4) app.Run();
(1)からは、ビルダーオブジェクトの生成と、サービスコレクションへのコントローラ利用の追加、Swaggerジェネレータの追加を行っています。Swaggerジェネレータとは、ルート、コントローラ、モデルからSwaggerDocumentオブジェクト(Swaggerで利用するOASに基づくデータ)を構築するクラスです。
(2)からは、アプリケーションオブジェクトの生成と、DebugターゲットでのみSwagger UIなどのミドルウェアを有効にする設定を行っています。Swaggerの利用には、(1)におけるSwaggerジェネレータの追加と、ここでの有効化が必要になります。
(3)では、認証の利用を設定しています。既定では認証が必要なクラスはありませんが、[Authorize]属性をコントローラクラスやメソッドに付与する場合に必要な呼び出しです。
(4)では、属性ルーティングのマッピングを行っています。この呼び出しによって、コントローラクラスやメソッドに設定された属性ルーティングが有効になります。
具体的な例は省きますが、第7回までのようにFootmarkモデル(Footmark.cs)を追加し、Scaffoldingを行うことで、基本的なCRUD機能を備えた「足あとAPI」と言えるものを構築できます。必要なNugetパッケージはこれまでと同様なので、試してみるのもよいでしょう。Scaffoldingのためのコマンドは、以下になります。
% dotnet aspnet-codegenerator controller -name FootmarkController -async -api -m Footmark -dc FootmarkContext -outDir Controllers -sqlite
まとめ
今回は、ASP.NET CoreにおけるWeb APIのためのフレームワークである、コントローラベースのWeb APIについて見てきました。次回は、.NET 6からサポートされたMinimal APIとこれらのAPIを利用するSPAのテンプレートについて紹介します。