演習 - コントローラーを追加する
controller は、"アクション" と呼ばれる 1 つまたは複数のパブリック メソッドを含むパブリック クラスです。 規約により、コントローラーはプロジェクト ルートの Controllers ディレクトリに配置します。 アクションは、Web API コントローラー内の HTTP エンドポイントとして公開されます。
コントローラーの作成
Visual Studio Code で Controllers フォルダーを選んで、PizzaController.cs という名前の新しいファイルを追加します。
PizzaController.cs という名前の空のクラス ファイルが、Controllers ディレクトリに作成されます。 Controllers というディレクトリ名は規約で決まっています。 ディレクトリ名の由来は、Web API で使用している Model-View-Controller アーキテクチャです。
Note
規約により、コントローラー クラスの名前には Controller というサフィックスが付きます。
Controllers/PizzaController.cs に次のコードを追加します。 変更を保存します。
using ContosoPizza.Models; using ContosoPizza.Services; using Microsoft.AspNetCore.Mvc; namespace ContosoPizza.Controllers; [ApiController] [Route("[controller]")] public class PizzaController : ControllerBase { public PizzaController() { } // GET all action // GET by Id action // POST action // PUT action // DELETE action }
前に学習したように、このクラスは、ASP.NET Core で HTTP 要求を処理するための基底クラスである
ControllerBase
から派生します。 また、学習した 2 つの標準属性[ApiController]
と[Route]
も含まれます。 前と同様に、[Route]
属性で、[controller]
トークンへのマッピングを定義します。 このコントローラー クラスはPizzaController
という名前であるため、このコントローラーはhttps://localhost:{PORT}/pizza
への要求を処理します。
すべてのピザを取得する
実装する必要がある最初の REST 動詞は、クライアントが API からすべてのピザを取得できる GET
です。 組み込みの [HttpGet]
属性を使用して、このサービスからピザを返すメソッドを定義できます。
Controllers/PizzaController.cs 内の // GET all action
のコメントを次のコードに置き換えます。
[HttpGet]
public ActionResult<List<Pizza>> GetAll() =>
PizzaService.GetAll();
上記のアクションでは、次のことが行われます。
[HttpGet]
属性で示されているように、HTTPGET
動詞にのみ応答します。- 型
List<Pizza>
のActionResult
インスタンスを返します。ActionResult
型は ASP.NET Core のすべてのアクション結果の基本クラスです。 - サービスに対してすべてのピザのクエリを実行し、
Content-Type
の値をapplication/json
にしてデータを自動的に返します。
単一のピザを取得する
クライアントは、リスト全体ではなく、特定のピザに関する情報を要求することもあります。 id
パラメーターを必要とする別の GET
アクションを実装できます。 組み込みの [HttpGet("{id}")]
属性を使用して、このサービスからピザを返すメソッドを定義できます。 ルーティング ロジックで、[HttpGet]
(id
なし) と [HttpGet("{id}")]
(id
あり) を 2 つの異なるルートとして登録します。 次に、単一の項目を取得する個別のアクションを記述できます。
Controllers/PizzaController.cs 内の // GET by Id action
のコメントを次のコードに置き換えます。
[HttpGet("{id}")]
public ActionResult<Pizza> Get(int id)
{
var pizza = PizzaService.Get(id);
if(pizza == null)
return NotFound();
return pizza;
}
上記のアクションでは、次のことが行われます。
[HttpGet]
属性で示されているように、HTTPGET
動詞にのみ応答します。- URL セグメントの
pizza/
の後に、id
パラメーターの値が含まれている必要があります。 コントローラー レベルの[Route]
属性で/pizza
パターンが定義されていたことを思い出してください。 - データベースに対して、指定された
id
パラメーターに一致するピザのクエリを実行します。
上記のアクションで使用されている ActionResult
の各インスタンスは、次の表の対応する HTTP 状態コードにマップされます。
ASP.NET Core アクションの結果 |
HTTP 状態コード | 説明 |
---|---|---|
Ok が暗示されます |
200 | 指定された id パラメーターに一致する商品が、メモリ内キャッシュに存在します。商品は、 accept HTTP 要求ヘッダーで定義されているメディアの種類で応答本文に含まれます (既定では JSON)。 |
NotFound |
404 | 指定された id パラメーターに一致する商品が、メモリ内キャッシュに存在しません。 |
新しいコントローラーをビルドして実行する
次のコマンドを実行して、Web API をビルドして開始します。
dotnet run
Http ファイルを使用してコントローラーをテストする
ContosoPizza.http を開きます
### 区切り記号の下で
Pizza
エンドポイントを呼び出す新しい GET を追加します。GET {{ContosoPizza_HostAddress}}/pizza/ Accept: application/json ###
この新しい GET 呼び出しの上にある [要求の送信] コマンドを選択します。
上のコマンドからは、すべてのピザの一覧が JSON で返されます。
HTTP/1.1 200 OK Connection: close Content-Type: application/json; charset=utf-8 Date: Wed, 17 Jan 2024 16:57:09 GMT Server: Kestrel Transfer-Encoding: chunked [ { "id": 1, "name": "Classic Italian", "isGlutenFree": false }, { "id": 2, "name": "Veggie", "isGlutenFree": true } ]
1 つのピザのクエリを実行するには、別の
GET
要求を行うことができますが、次のコマンドを使用してid
パラメーターを渡します。GET {{ContosoPizza_HostAddress}}/pizza/1 Accept: application/json ###
上のコマンドからは、次の出力を含む
Classic Italian
が返されます。HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Fri, 02 Apr 2021 21:57:57 GMT Server: Kestrel Transfer-Encoding: chunked { "id": 1, "name": "Classic Italian", "isGlutenFree": false }
この API では、項目が存在しない状況も処理されます。 もう一度 API を呼び出しますが、次のコマンドを使用して無効なピザ
id
パラメーターを渡します。GET {{ContosoPizza_HostAddress}}/pizza/5 Accept: application/json ###
前のコマンドからは、
404 Not Found
エラーと次の出力が返されます。HTTP/1.1 404 Not Found Content-Type: application/problem+json; charset=utf-8 Date: Fri, 02 Apr 2021 22:03:06 GMT Server: Kestrel Transfer-Encoding: chunked { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4", "title": "Not Found", "status": 404, "traceId": "00-ec263e401ec554b6a2f3e216a1d1fac5-4b40b8023d56762c-00" }
これで、GET
動詞の実装が完了しました。 次のユニットでは、さらにアクションを PizzaController
に追加して、ピザ データに対する CRUD 操作をサポートできます。
省略可能:コマンド ライン HTTP Read-Eval-Print Loop (REPL) を使用してコントローラーをテストする
既存の
httprepl
ターミナルを開くか、Visual Studio Code のメイン メニューから [ターミナル]>[新しいターミナル] を選んで新しい統合ターミナルを開きます。次のコマンドを実行して、Web API に接続します。
httprepl https://localhost:{PORT}
または、
HttpRepl
の実行中に次のコマンドを実行します。connect https://localhost:{PORT}
新しく使用可能になった
Pizza
エンドポイントを確認するには、次のコマンドを実行します。ls
上記のコマンドにより、接続されたエンドポイントで使用可能なすべての API が検出されます。 次のコードが表示されます。
https://localhost:{PORT}/> ls . [] Pizza [GET] WeatherForecast [GET]
次のコマンドを実行して、
Pizza
エンドポイントに移動します。cd Pizza
上のコマンドを実行すると、
Pizza
エンドポイントで使用可能な API が示されます。https://localhost:{PORT}/> cd Pizza /Pizza [GET]
次のコマンドを使用して、
HttpRepl
でGET
要求を行います。get
上のコマンドからは、すべてのピザの一覧が JSON で返されます。
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Fri, 02 Apr 2021 21:55:53 GMT Server: Kestrel Transfer-Encoding: chunked [ { "id": 1, "name": "Classic Italian", "isGlutenFree": false }, { "id": 2, "name": "Veggie", "isGlutenFree": true } ]
1 つのピザのクエリを実行するには、別の
GET
要求を行うことができますが、次のコマンドを使用してid
パラメーターを渡します。get 1
上のコマンドからは、次の出力を含む
Classic Italian
が返されます。HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Fri, 02 Apr 2021 21:57:57 GMT Server: Kestrel Transfer-Encoding: chunked { "id": 1, "name": "Classic Italian", "isGlutenFree": false }
この API では、項目が存在しない状況も処理されます。 もう一度 API を呼び出しますが、次のコマンドを使用して無効なピザ
id
パラメーターを渡します。get 5
前のコマンドからは、
404 Not Found
エラーと次の出力が返されます。HTTP/1.1 404 Not Found Content-Type: application/problem+json; charset=utf-8 Date: Fri, 02 Apr 2021 22:03:06 GMT Server: Kestrel Transfer-Encoding: chunked { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4", "title": "Not Found", "status": 404, "traceId": "00-ec263e401ec554b6a2f3e216a1d1fac5-4b40b8023d56762c-00" }
Visual Studio Code のドロップダウン リストで
dotnet
ターミナルに戻り、キーボードで Ctrl + C キーを押して Web API をシャットダウンします。
これで、GET
動詞の実装が完了しました。 次のユニットでは、さらにアクションを PizzaController
に追加して、ピザ データに対する CRUD 操作をサポートできます。