注
これは、この記事の最新バージョンではありません。 現在のリリースについては、 この記事の .NET 9 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、 .NET および .NET Core サポート ポリシーを参照してください。 現在のリリースについては、 この記事の .NET 9 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、 この記事の .NET 9 バージョンを参照してください。
Tim Deschryver と Rick Anderson
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小限の API とコントローラー ベースの API の選択に関するヘルプについては、 API の概要を参照してください。 最小限の API の作成に関するチュートリアルについては、「 チュートリアル: ASP.NET Core を使用して最小限の API を作成する」を参照してください。
概要
このチュートリアルでは、次の API を作成します。
API(アプリケーション・プログラミング・インターフェース) | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | 無し | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | 無し | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | 無し |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | 無し | 無し |
次の図は、アプリのデザインを示しています。
前提条件
ASP.NET および Web 開発ワークロードを含む Visual Studio 2022。
Web API プロジェクトを作成する
- [ ファイル ] メニューの [ 新規>プロジェクト] を選択します。
- 検索ボックスに 「Web API 」と入力します。
- ASP.NET Core Web API テンプレートを選択し、[次へ] を選択します。
- [ 新しいプロジェクトの構成] ダイアログで、プロジェクト に TodoApi という名前を付け、[ 次へ] を選択します。
- [追加情報] ダイアログで、次の 手順 を実行します。
- フレームワークが .NET 9.0 (Standard Term Support) であることを確認します。
- [OpenAPI サポート を有効にする
のチェック ボックスがオンになっていることを確認します。 - [コントローラーを使用する] のチェックボックス (最小限の API を使用するにはオフ) が オンになっていることを確認します。
- 作成を選択します。
NuGet パッケージの追加
このチュートリアルで使うデータベースをサポートするには、NuGet パッケージを追加する必要があります。
- [ ツール ] メニューの [ NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] を選択します。
- [参照] タブを選択します。
- 検索ボックスに 「Microsoft.EntityFrameworkCore.InMemory 」と入力し、
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [ プロジェクト ] チェック ボックスをオンにし、[ インストール] を選択します。
注
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトを実行する
プロジェクト テンプレートは、WeatherForecast
をサポートする API を作成します。
Ctrl + F5 キーを押して、デバッガーなしで実行します。
SSL を使用するようにプロジェクトがまだ構成されていない場合、Visual Studio に次のダイアログが表示されます。
IIS Express SSL 証明書を信頼する場合は、[ はい ] を選択します。
次のダイアログが表示されます。
開発証明書を信頼することに同意する場合は、[ はい ] を選択します。
Firefox ブラウザーを信頼する方法については、 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE証明書エラーに関する記事を参照してください。
Visual Studio によってターミナル ウィンドウが起動され、実行中のアプリの URL が表示されます。 API は https://localhost:<port>
でホストされます。 <port>
は、プロジェクトの作成時にランダムに選択されたポート番号セットです。
...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7260
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:7261
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
...
+で HTTPS URL をクリックして、ブラウザーで Web アプリをテストします。
https://localhost:<port>
にエンドポイントがないため、ブラウザーは HTTP 404 Not Found を返します。
URL に /weatherforecast
を追加して WeatherForecast API をテストします。
ブラウザーには、次の例のような JSON が表示されます。
[
{
"date": "2025-07-16",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2025-07-17",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2025-07-18",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2025-07-19",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2025-07-20",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
プロジェクトをテストする
このチュートリアルでは 、エンドポイント エクスプローラーと .http ファイル を使用して API をテストします。
モデル クラスの追加
モデルは、アプリが管理するデータを表すクラスのセットです。 このアプリのモデルは、TodoItem
クラスです。
- ソリューション エクスプローラー で、プロジェクトを右クリックします。 [ 追加>新しいフォルダー] を選択します。 フォルダーに「
Models
で行うことができます。 -
Models
フォルダーを右クリックし、[追加>Class] を選択します。 クラスに TodoItem という名前を付 け、[追加] を選択します。 - テンプレート コードを次のコードに置き換えます。
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Id
プロパティは、リレーショナル データベース内の一意のキーとして機能します。
モデル クラスはプロジェクト内のどこでも使用できますが、慣例により Models
フォルダーが使用されます。
データベース コンテキストの追加
データベース コンテキストは、データ モデルの Entity Framework 機能を調整するメイン クラスです。 このクラスは Microsoft.EntityFrameworkCore.DbContext クラスから派生させて作成します。
Models
フォルダーを右クリックし、[追加>Class] を選択します。 クラス に TodoContext という名前を 付け、[追加] をクリックします。次のコードを入力します。
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
データベース コンテキストの登録
ASP.NET Core では、DB コンテキストなどのサービスを 依存関係挿入 (DI) コンテナーに登録する必要があります。 コンテナーは、コントローラーにサービスを提供します。
次の強調表示されているコードを使用して、Program.cs
を更新します。
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
上記のコードでは次の操作が行われます。
-
using
ディレクティブを追加します。 - DI コンテナーにデータベース コンテキストを追加します。
- データベース コンテキストがメモリ内データベースを使用することを指定します。
コントローラーのスキャフォールディング
Controllers
フォルダーを右クリックしします。[を選択します。
Entity Framework を使用して、アクションを含む API コントローラーを選択し、[追加] を選択します。
[Entity Framework を使用したアクションを含む API コントローラーの追加] ダイアログで、次の操作を行います。
- Model クラスで TodoItem (TodoApi.Models) を選択します。
- データ コンテキスト クラスで TodoContext (TodoApi.Models) を選択します。
- 追加を選択します。
スキャフォールディング操作が失敗した場合は、[ 追加 ] を選択して、もう一度スキャフォールディングを試みます。
この手順では、プロジェクトに Microsoft.VisualStudio.Web.CodeGeneration.Design
と Microsoft.EntityFrameworkCore.Tools
NuGet パッケージを追加します。
これらのパッケージは、スキャフォールディングに必要です。
生成されたコードでは次の操作が行われます。
- クラスを
[ApiController]
属性でマークします。 この属性は、コントローラーが Web API 要求に応答することを示します。 属性が有効にする特定の動作については、「 ASP.NET Core を使用した Web API の作成」を参照してください。 - DI を使用して、データベース コンテキスト (
TodoContext
) をコントローラーに挿入します。 データベース コンテキストは、コントローラー内の各 CRUD メソッドで使用されます。
ASP.NET Core テンプレートの対象は次のとおりです。
- ビューを含むコントローラーには、ルート テンプレートの
[action]
が含まれます。 - API コントローラーには、ルート テンプレートの
[action]
が含まれません。
[action]
トークンがルート テンプレートにない場合、アクション名 (メソッド名) はエンドポイントに含まれません。 つまり、アクションの関連付けられたメソッド名は一致するルートでは使用されません。
PostTodoItem 作成メソッドの更新
PostTodoItem
演算子を使用するために、 で return ステートメントを更新します。
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
HTTP POST
属性が示すように、上記のコードは [HttpPost]
メソッドです。 このメソッドは、HTTP 要求の本文から TodoItem
の値を取得します。
詳細については、「 Http[Verb] 属性を使用した属性ルーティング」を参照してください。
CreatedAtAction メソッド:
- 成功した場合は 、HTTP 201 状態コード を返します。
HTTP 201
は、サーバーに新しいリソースを作成するHTTP POST
メソッドに対する標準の応答です。 -
Location ヘッダーを応答に追加します。
Location
ヘッダーは、新しく作成された to-do 項目の URI を指定します。 詳細については、「 10.2.2 201 Created」を参照してください。 -
GetTodoItem
アクションを参照してLocation
ヘッダーの URI を作成します。 C# のnameof
キーワードを使って、CreatedAtAction
呼び出しでアクション名をハードコーディングすることを回避しています。
PostTodoItem のテスト
表示>メニューを選択し、その他のウィンドウ>からEndpoints Explorerを選びます。
POST エンドポイントを右クリックし、[要求の生成] を選択します。
次の例のような内容の
TodoApi.http
という新しいファイルがプロジェクト フォルダー内に作成されます。@TodoApi_HostAddress = https://localhost:49738 POST {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { //TodoItem } ###
- 最初の行では、すべてのエンドポイントに使われる変数を作成します。
- 次の行では、POST 要求を定義しています。
- POST 要求行の後の行は、ヘッダーと要求本文のプレースホルダーを定義します。
- トリプル ハッシュタグ (
###
) 行は要求の区切り記号であり、この後に続くのは別の要求向けのものです。
POST 要求では、
TodoItem
が必要です。 todo を定義するには、//TodoItem
コメントを次の JSON に置き換えます。{ "name": "walk dog", "isComplete": true }
TodoApi.http ファイルは次の例のようになりますが、実際のポート番号に置き換えてください。
@TodoApi_HostAddress = https://localhost:7260 Post {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { "name": "walk dog", "isComplete": true } ###
アプリを実行します。
要求行の上にある
POST
リンクを選択します。POST 要求がアプリに送信され、応答ウィンドウに 応答 が表示されます。
場所ヘッダー URI のテスト
ブラウザーから GET
エンドポイントを呼び出すか、 エンドポイント エクスプローラーを使用して、アプリをテストします。 エンドポイント エクスプローラーの手順を次 に示します。
エンドポイント エクスプローラーで、最初の GET エンドポイントを右クリックし、[要求の生成] を選択します。
次の内容が
TodoApi.http
ファイルに追加されます。GET {{TodoApi_HostAddress}}/api/todoitems ###
新しい 要求行の上にある
GET
リンクを選択します。GET 要求がアプリに送信され、応答ウィンドウに 応答 が表示されます。
応答本文は次の JSON のようになります。
[ { "id": 1, "name": "walk dog", "isComplete": true } ]
エンドポイント エクスプローラーで、
/api/todoitems/{id}
GET エンドポイントを右クリックし、[要求の生成] を選択します。 次の内容がTodoApi.http
ファイルに追加されます。@id=0 GET {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
(
{@id}
ではなく)1
に0
を割り当てます。新しい GET 要求行の上にある [要求の送信] リンクを選択します。
GET 要求がアプリに送信され、応答ウィンドウに 応答 が表示されます。
応答本文は次の JSON のようになります。
{ "id": 1, "name": "walk dog", "isComplete": true }
GET メソッドの確認
2 つの GET エンドポイントが実装されます。
GET /api/todoitems
GET /api/todoitems/{id}
前のセクションでは、/api/todoitems/{id}
ルートの例を示しました。
POST の指示に従って別の todo 項目を追加し、Swagger を使用して/api/todoitems
ルートをテストします。
このアプリではメモリ内データベースが使用されます。 アプリが停止して開始された場合、上記の GET 要求はどのようなデータも返しません。 データが返されない場合は、アプリに データを POST します。
ルーティングと URL パス
[HttpGet]
属性は、HTTP GET
要求に応答するメソッドを表します。 各メソッドの URL パスは次のように構成されます。
コントローラーの
Route
属性でテンプレート文字列を使用します。[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
[controller]
をコントローラーの名前 (慣例では "Controller" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsコントローラーであるため、コントローラー名は "TodoItems" です。 ASP.NET Core ルーティング では大文字と小文字が区別されません。[HttpGet]
属性にルート テンプレート (たとえば、[HttpGet("products")]
) がある場合は、それをパスに追加します。 このサンプルではテンプレートを使用しません。 詳細については、「 Http[Verb] 属性を使用した属性ルーティング」を参照してください。
次の GetTodoItem
メソッドで、"{id}"
は To Do アイテムの一意識別子に使用するプレースホルダーの変数です。
GetTodoItem
が呼び出されると、その "{id}"
パラメーター内のメソッドに URL の id
の値が指定されます。
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
戻り値
GetTodoItems
メソッドと GetTodoItem
メソッドの戻り値の型は ActionResult<T> 型です。 ASP.NET Core は、オブジェクトを JSON に自動的にシリアル化し、応答メッセージの本文に JSON を書き込みます。 この戻り値の型の応答コードは 200 OK です。ハンドルされない例外がないと仮定します。 ハンドルされない例外は 5xx エラーに変換されます。
ActionResult
戻り値の型は、幅広い範囲の HTTP 状態コードを表すことができます。 たとえば、GetTodoItem
は、次の 2 つの異なる状態値を返す可能性があります。
- 要求された ID と一致する項目がない場合、メソッドは 404 状態NotFound エラー コードを返します。
- それ以外の場合、メソッドは JSON 応答本文で 200 を返します。 戻り値が
item
の場合、HTTP 200
応答が返されます。
PutTodoItem メソッド
PutTodoItem
メソッドを検証します。
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
は PostTodoItem
と似ていますが、HTTP PUT
を使用します。 応答は 204 (コンテンツなし) です。 HTTP 仕様に従って、PUT
要求では、変更だけでなく、更新されたエンティティ全体を送信するようクライアントに求めます。 部分的な更新をサポートするには、 HTTP PATCH を使用します。
PutTodoItem メソッドのテスト
このサンプルでは、アプリを起動するたびに開始することが必要なメモリ内データベースが使われています。 PUT 呼び出しを実行する前に、データベース内にアイテムが存在している必要があります。 GET を呼び出して、PUT 呼び出しを実行する前にデータベース内にアイテムが確実に存在していることを確認します。
id = 1 のPUT
を更新し、その名前を TodoItem
に設定するには、"feed fish"
メソッドを使用します。 応答は HTTP 204 No Content
であることに注意してください。
エンドポイント エクスプローラーでPUT エンドポイントを右クリックし、[要求の生成] を選択します。
次の内容が
TodoApi.http
ファイルに追加されます。PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}} Content-Type: application/json { //TodoItem } ###
PUT 要求行の
{{id}}
を1
に置き換えます。//TodoItem
プレースホルダーを次の行に置き換えます。PUT {{TodoApi_HostAddress}}/api/todoitems/1 Content-Type: application/json { "id": 1, "name": "feed fish", "isComplete": false }
新しい PUT 要求行の上にある [要求の 送信] リンクを選択します。
PUT 要求がアプリに送信され、応答ウィンドウに 応答 が表示されます。 応答本文は空であり、状態コードは 204 です。
DeleteTodoItem メソッド
DeleteTodoItem
メソッドを検証します。
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
DeleteTodoItem メソッドのテスト
id = 1 のDELETE
を削除するには、TodoItem
メソッドを使用します。 応答は HTTP 204 No Content
であることに注意してください。
エンドポイント エクスプローラーで、DELETE エンドポイントを右クリックし、[要求の生成] を選択します。
DELETE 要求が
TodoApi.http
に追加されます。DELETE 要求行の
{{id}}
を1
に置き換えます。 DELETE 要求は次の例のようになります。DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
DELETE リクエスト用の 要求の送信 リンクを選択します。
DELETE 要求がアプリに送信され、応答ウィンドウに 応答 が表示されます。 応答本文は空であり、状態コードは 204 です。
他のツールでテストする
Web API のテストには、他にも使用できるツールが多数あります。次に例を示します。
過剰な投稿を防止する
現在、サンプル アプリでは TodoItem
オブジェクト全体が公開されています。 通常、運用環境のアプリでは、モデルのサブセットを使用して入力されるデータおよび返されるデータが制限されています。 その背景には複数の理由があり、セキュリティは主なものです。 モデルのサブセットは、通常、データ転送オブジェクト (DTO)、入力モデル、またはビュー モデルと呼ばれます。 このチュートリアルでは DTO を使用します。
DTO は次の目的で使用できます。
- 過剰な投稿を防止する。
- クライアントが表示しないことになっているプロパティを非表示にする。
- ペイロード サイズを減らすために、いくつかのプロパティを省略する。
- 入れ子になったオブジェクトを含むオブジェクト グラフをフラット化する。 フラット化されたオブジェクト グラフは、クライアントにとってより便利になる可能性があります。
DTO のアプローチを実演するために、TodoItem
クラスを更新して、シークレット フィールドを含めます。
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
シークレット フィールドは、このアプリでは非表示にする必要がありますが、管理アプリの場合は公開することを選択できます。
シークレット フィールドを投稿および取得できることを確認します。
Models/TodoItemsDTO.cs ファイルに DTO モデルを作成します。
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemsController
を使用するように TodoItemDTO
を更新します。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
シークレット フィールドを投稿または取得できないことを確認します。
JavaScript を使用した Web API の呼び出し
「 チュートリアル: JavaScript を使用して ASP.NET Core Web API を呼び出す」を参照してください。
Web API ビデオ シリーズ
ビデオ: 初心者向けシリーズ:Web API を参照してください。
エンタープライズ Web アプリのパターン
信頼性が高く、セキュリティで保護され、パフォーマンスが高く、テスト可能でスケーラブルな ASP.NET Core アプリの作成に関するガイダンスについては、 エンタープライズ Web アプリのパターンに関するページを参照してください。 パターンを実装する完全な運用品質のサンプル Web アプリを使用できます。
Web API に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- フェデレーション ゲートウェイ
重要
Duende ソフトウェアでは、DuendeIdentity Server の運用環境での使用に対するライセンス料金の支払いが必要になる場合があります。 詳細については、「 .NET 5 の ASP.NET Core から .NET 6 への移行」を参照してください。
詳細については、 Duende Identity Server のドキュメント (Duende Software Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイの詳細については、「 クイック スタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロードする方法を参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使用して Web API を作成する
- チュートリアル: ASP.NET Core を使用して最小限の API を作成する
- 生成された OpenAPI ドキュメントを使用する
- Swagger/OpenAPI を使用した ASP.NET Core Web API ドキュメント
- Razor ASP.NET Core の Entity Framework Core を含むページ - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- ASP.NET Core アプリを Azure App Service にデプロイする
- ASP.NET Core のホストとデプロイ
- ASP.NET Core を使用して Web API を作成する
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小限の API とコントローラー ベースの API の選択に関するヘルプについては、 API の概要を参照してください。 最小限の API の作成に関するチュートリアルについては、「 チュートリアル: ASP.NET Core を使用して最小限の API を作成する」を参照してください。
概要
このチュートリアルでは、次の API を作成します。
API(アプリケーション・プログラミング・インターフェース) | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | 無し | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | 無し | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | 無し |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | 無し | 無し |
次の図は、アプリのデザインを示しています。
前提条件
ASP.NET および Web 開発ワークロードを含む Visual Studio 2022。
Web プロジェクトの作成
- [ ファイル ] メニューの [ 新規>プロジェクト] を選択します。
- 検索ボックスに 「Web API 」と入力します。
- ASP.NET Core Web API テンプレートを選択し、[次へ] を選択します。
- [ 新しいプロジェクトの構成] ダイアログで、プロジェクト に TodoApi という名前を付け、[ 次へ] を選択します。
- [追加情報] ダイアログで、次の 手順 を実行します。
- フレームワークが .NET 8.0 (長期サポート) であることを確認します。
- [コントローラーを使用する( 最小限の API を使用する場合はオフ)] チェックボックスがオンになっていることを確認します。
- [OpenAPI サポート を有効にする
のチェック ボックスがオンになっていることを確認します。 - 作成を選択します。
NuGet パッケージの追加
このチュートリアルで使うデータベースをサポートするには、NuGet パッケージを追加する必要があります。
- [ ツール ] メニューの [ NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] を選択します。
- [参照] タブを選択します。
- 検索ボックスに 「Microsoft.EntityFrameworkCore.InMemory 」と入力し、
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [ プロジェクト ] チェック ボックスをオンにし、[ インストール] を選択します。
注
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトをテストする
プロジェクト テンプレートにより、WeatherForecast
をサポートする API が作成されます。
Ctrl + F5 キーを押して、デバッガーなしで実行します。
SSL を使用するようにプロジェクトがまだ構成されていない場合、Visual Studio に次のダイアログが表示されます。
IIS Express SSL 証明書を信頼する場合は、[ はい ] を選択します。
次のダイアログが表示されます。
開発証明書を信頼することに同意する場合は、[ はい ] を選択します。
Firefox ブラウザーを信頼する方法については、 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE証明書エラーに関する記事を参照してください。
Visual Studio で既定のブラウザーが起動し、https://localhost:<port>/swagger/index.html
にアクセスします。ここで、<port>
は、プロジェクト作成時に設定したランダムに選択されたポート番号になります。
Swagger ページ /swagger/index.html
が表示されます。
GET>試してみる>実行 を選択します。 ページに以下が表示されます。
- WeatherForecast API をテストする Curl コマンド。
- WeatherForecast API をテストする URL。
- 応答コード、本文、およびヘッダー。
- メディアの種類と、値とスキーマの例を含むドロップダウン リスト ボックス。
Swagger ページが表示されない場合は、 この GitHub の問題を参照してください。
Swagger は、Web API の有用なドキュメントやヘルプ ページを生成するために使用されます。 このチュートリアルでは、Swagger を使ってアプリをテストします。 Swagger の詳細については、Swagger /OpenAPI ASP.NET Core Web API のドキュメントを参照してください。
要求 URL をコピーしてブラウザーに貼り付けます。https://localhost:<port>/weatherforecast
次の例のような JSON が返されます。
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
モデル クラスの追加
モデルは、アプリが管理するデータを表すクラスのセットです。 このアプリのモデルは、TodoItem
クラスです。
- ソリューション エクスプローラー で、プロジェクトを右クリックします。 [ 追加>新しいフォルダー] を選択します。 フォルダーに「
Models
で行うことができます。 -
Models
フォルダーを右クリックし、[追加>Class] を選択します。 クラスに TodoItem という名前を付 け、[追加] を選択します。 - テンプレート コードを次のコードに置き換えます。
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Id
プロパティは、リレーショナル データベース内の一意のキーとして機能します。
モデル クラスはプロジェクト内のどこでも使用できますが、慣例により Models
フォルダーが使用されます。
データベース コンテキストの追加
データベース コンテキストは、データ モデルの Entity Framework 機能を調整するメイン クラスです。 このクラスは Microsoft.EntityFrameworkCore.DbContext クラスから派生させて作成します。
-
Models
フォルダーを右クリックし、[追加>Class] を選択します。 クラス に TodoContext という名前を 付け、[追加] をクリックします。
次のコードを入力します。
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
データベース コンテキストの登録
ASP.NET Core では、DB コンテキストなどのサービスを 依存関係挿入 (DI) コンテナーに登録する必要があります。 コンテナーは、コントローラーにサービスを提供します。
次の強調表示されているコードを使用して、Program.cs
を更新します。
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
上記のコードでは次の操作が行われます。
-
using
ディレクティブを追加します。 - DI コンテナーにデータベース コンテキストを追加します。
- データベース コンテキストがメモリ内データベースを使用することを指定します。
コントローラーのスキャフォールディング
Controllers
フォルダーを右クリックしします。[を選択します。
Entity Framework を使用して、アクションを含む API コントローラーを選択し、[追加] を選択します。
[Entity Framework を使用したアクションを含む API コントローラーの追加] ダイアログで、次の操作を行います。
- Model クラスで TodoItem (TodoApi.Models) を選択します。
- データ コンテキスト クラスで TodoContext (TodoApi.Models) を選択します。
- 追加を選択します。
スキャフォールディング操作が失敗した場合は、[ 追加 ] を選択して、もう一度スキャフォールディングを試みます。
生成されたコードでは次の操作が行われます。
- クラスを
[ApiController]
属性でマークします。 この属性は、コントローラーが Web API 要求に応答することを示します。 属性が有効にする特定の動作については、「 ASP.NET Core を使用した Web API の作成」を参照してください。 - DI を使用して、データベース コンテキスト (
TodoContext
) をコントローラーに挿入します。 データベース コンテキストは、コントローラー内の各 CRUD メソッドで使用されます。
ASP.NET Core テンプレートの対象は次のとおりです。
- ビューを含むコントローラーには、ルート テンプレートの
[action]
が含まれます。 - API コントローラーには、ルート テンプレートの
[action]
が含まれません。
[action]
トークンがルート テンプレートにない場合、アクション名 (メソッド名) はエンドポイントに含まれません。 つまり、アクションの関連付けられたメソッド名は一致するルートでは使用されません。
PostTodoItem 作成メソッドの更新
PostTodoItem
演算子を使用するために、 で return ステートメントを更新します。
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
HTTP POST
属性が示すように、上記のコードは [HttpPost]
メソッドです。 このメソッドは、HTTP 要求の本文から TodoItem
の値を取得します。
詳細については、「 Http[Verb] 属性を使用した属性ルーティング」を参照してください。
CreatedAtAction メソッド:
- 成功した場合は 、HTTP 201 状態コード を返します。
HTTP 201
は、サーバーに新しいリソースを作成するHTTP POST
メソッドに対する標準の応答です。 -
Location ヘッダーを応答に追加します。
Location
ヘッダーは、新しく作成された to-do 項目の URI を指定します。 詳細については、「 10.2.2 201 Created」を参照してください。 -
GetTodoItem
アクションを参照してLocation
ヘッダーの URI を作成します。 C# のnameof
キーワードを使って、CreatedAtAction
呼び出しでアクション名をハードコーディングすることを回避しています。
PostTodoItem のテスト
Ctrl キーを押しながら F5 キーを押して、アプリを実行します。
Swagger ブラウザー ウィンドウで、 POST /api/TodoItems を選択し、[ 試してみる] を選択します。
要求本文の入力ウィンドウで、JSON を更新します。 たとえば、 にします。
{ "name": "walk dog", "isComplete": true }
[ 実行] を選択する
場所ヘッダー URI のテスト
前の POST では、Swagger UI は応答ヘッダーの下に 場所ヘッダー を表示 します。 たとえば、「 location: https://localhost:7260/api/TodoItems/1
」のように入力します。 場所ヘッダーには、作成されたリソースへの URI が表示されます。
場所ヘッダーをテストするには:
Swagger ブラウザー ウィンドウで、 GET /api/TodoItems/{id} を選択し、[ 試してみる] を選択します。
1
入力ボックスに「id
」と入力し、[実行] を選択します。
GET メソッドの確認
2 つの GET エンドポイントが実装されます。
GET /api/todoitems
GET /api/todoitems/{id}
前のセクションでは、/api/todoitems/{id}
ルートの例を示しました。
POST の指示に従って別の todo 項目を追加し、Swagger を使用して/api/todoitems
ルートをテストします。
このアプリではメモリ内データベースが使用されます。 アプリが停止して開始された場合、上記の GET 要求はどのようなデータも返しません。 データが返されない場合は、アプリに データを POST します。
ルーティングと URL パス
[HttpGet]
属性は、HTTP GET
要求に応答するメソッドを表します。 各メソッドの URL パスは次のように構成されます。
コントローラーの
Route
属性でテンプレート文字列を使用します。[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
[controller]
をコントローラーの名前 (慣例では "Controller" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsコントローラーであるため、コントローラー名は "TodoItems" です。 ASP.NET Core ルーティング では大文字と小文字が区別されません。[HttpGet]
属性にルート テンプレート (たとえば、[HttpGet("products")]
) がある場合は、それをパスに追加します。 このサンプルではテンプレートを使用しません。 詳細については、「 Http[Verb] 属性を使用した属性ルーティング」を参照してください。
次の GetTodoItem
メソッドで、"{id}"
は To Do アイテムの一意識別子に使用するプレースホルダーの変数です。
GetTodoItem
が呼び出されると、その "{id}"
パラメーター内のメソッドに URL の id
の値が指定されます。
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
戻り値
GetTodoItems
メソッドと GetTodoItem
メソッドの戻り値の型は ActionResult<T> 型です。 ASP.NET Core は、オブジェクトを JSON に自動的にシリアル化し、応答メッセージの本文に JSON を書き込みます。 この戻り値の型の応答コードは 200 OK です。ハンドルされない例外がないと仮定します。 ハンドルされない例外は 5xx エラーに変換されます。
ActionResult
戻り値の型は、幅広い範囲の HTTP 状態コードを表すことができます。 たとえば、GetTodoItem
は、次の 2 つの異なる状態値を返す可能性があります。
- 要求された ID と一致する項目がない場合、メソッドは 404 状態NotFound エラー コードを返します。
- それ以外の場合、メソッドは JSON 応答本文で 200 を返します。 戻り値が
item
の場合、HTTP 200
応答が返されます。
PutTodoItem メソッド
PutTodoItem
メソッドを検証します。
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
は PostTodoItem
と似ていますが、HTTP PUT
を使用します。 応答は 204 (コンテンツなし) です。 HTTP 仕様に従って、PUT
要求では、変更だけでなく、更新されたエンティティ全体を送信するようクライアントに求めます。 部分的な更新をサポートするには、 HTTP PATCH を使用します。
PutTodoItem メソッドのテスト
このサンプルでは、アプリを起動するたびに開始することが必要なメモリ内データベースが使われています。 PUT 呼び出しを実行する前に、データベース内にアイテムが存在している必要があります。 GET を呼び出して、PUT 呼び出しを実行する前にデータベース内にアイテムが確実に存在していることを確認します。
Swagger UI を使用して、PUT ボタンを使用して Id = 1 の TodoItem
を更新し、その名前を "feed fish"
に設定します。 応答は HTTP 204 No Content
であることに注意してください。
DeleteTodoItem メソッド
DeleteTodoItem
メソッドを検証します。
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
DeleteTodoItem メソッドのテスト
Swagger UI を使用して、Id = 1 の TodoItem
を削除します。 応答は HTTP 204 No Content
であることに注意してください。
他のツールでテストする
Web API のテストには、他にも使用できるツールが多数あります。次に例を示します。
- Visual Studio エンドポイント エクスプローラーと .http ファイル
- http-repl
-
curl。 Swagger は
curl
を使い、送信されたcurl
コマンドを表示します。 - バイオリン弾き
詳細については、次を参照してください。
過剰な投稿を防止する
現在、サンプル アプリでは TodoItem
オブジェクト全体が公開されています。 通常、運用環境のアプリでは、モデルのサブセットを使用して入力されるデータおよび返されるデータが制限されています。 その背景には複数の理由があり、セキュリティは主なものです。 モデルのサブセットは、通常、データ転送オブジェクト (DTO)、入力モデル、またはビュー モデルと呼ばれます。 このチュートリアルでは DTO を使用します。
DTO は次の目的で使用できます。
- 過剰な投稿を防止する。
- クライアントが表示しないことになっているプロパティを非表示にする。
- ペイロード サイズを減らすために、いくつかのプロパティを省略する。
- 入れ子になったオブジェクトを含むオブジェクト グラフをフラット化する。 フラット化されたオブジェクト グラフは、クライアントにとってより便利になる可能性があります。
DTO のアプローチを実演するために、TodoItem
クラスを更新して、シークレット フィールドを含めます。
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
シークレット フィールドは、このアプリでは非表示にする必要がありますが、管理アプリの場合は公開することを選択できます。
シークレット フィールドを投稿および取得できることを確認します。
次のように DTO モデルを作成します。
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemsController
を使用するように TodoItemDTO
を更新します。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
シークレット フィールドを投稿または取得できないことを確認します。
JavaScript を使用した Web API の呼び出し
「 チュートリアル: JavaScript を使用して ASP.NET Core Web API を呼び出す」を参照してください。
Web API ビデオ シリーズ
ビデオ: 初心者向けシリーズ:Web API を参照してください。
エンタープライズ Web アプリのパターン
信頼性が高く、セキュリティで保護され、パフォーマンスが高く、テスト可能でスケーラブルな ASP.NET Core アプリの作成に関するガイダンスについては、 エンタープライズ Web アプリのパターンに関するページを参照してください。 パターンを実装する完全な運用品質のサンプル Web アプリを使用できます。
Web API に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- フェデレーション ゲートウェイ
重要
Duende ソフトウェアでは、DuendeIdentity Server の運用環境での使用に対するライセンス料金の支払いが必要になる場合があります。 詳細については、「 .NET 5 の ASP.NET Core から .NET 6 への移行」を参照してください。
詳細については、 Duende Identity Server のドキュメント (Duende Software Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイの詳細については、「 クイック スタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロードする方法を参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使用して Web API を作成する
- チュートリアル: ASP.NET Core を使用して最小限の API を作成する
- Swagger/OpenAPI を使用した ASP.NET Core Web API ドキュメント
- Razor ASP.NET Core の Entity Framework Core を含むページ - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- ASP.NET Core アプリを Azure App Service にデプロイする
- ASP.NET Core のホストとデプロイ
- ASP.NET Core を使用して Web API を作成する
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小限の API とコントローラー ベースの API の選択に関するヘルプについては、 API の概要を参照してください。 最小限の API の作成に関するチュートリアルについては、「 チュートリアル: ASP.NET Core を使用して最小限の API を作成する」を参照してください。
概要
このチュートリアルでは、次の API を作成します。
API(アプリケーション・プログラミング・インターフェース) | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | 無し | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | 無し | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | 無し |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | 無し | 無し |
次の図は、アプリのデザインを示しています。
前提条件
ASP.NET および Web 開発ワークロードを含む Visual Studio 2022。
Web プロジェクトの作成
- [ ファイル ] メニューの [ 新規>プロジェクト] を選択します。
- 検索ボックスに 「Web API 」と入力します。
- ASP.NET Core Web API テンプレートを選択し、[次へ] を選択します。
- [ 新しいプロジェクトの構成] ダイアログで、プロジェクト に TodoApi という名前を付け、[ 次へ] を選択します。
- [追加情報] ダイアログで、次の 手順 を実行します。
- フレームワークが .NET 8.0 (長期サポート) であることを確認します。
- [コントローラーを使用する( 最小限の API を使用する場合はオフ)] チェックボックスがオンになっていることを確認します。
- [OpenAPI サポート を有効にする
のチェック ボックスがオンになっていることを確認します。 - 作成を選択します。
NuGet パッケージの追加
このチュートリアルで使うデータベースをサポートするには、NuGet パッケージを追加する必要があります。
- [ ツール ] メニューの [ NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] を選択します。
- [参照] タブを選択します。
- 検索ボックスに 「Microsoft.EntityFrameworkCore.InMemory 」と入力し、
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [ プロジェクト ] チェック ボックスをオンにし、[ インストール] を選択します。
注
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ消費ワークフローでの パッケージのインストールと管理(NuGet ドキュメント)」の記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトをテストする
プロジェクト テンプレートにより、WeatherForecast
をサポートする API が作成されます。
Ctrl + F5 キーを押して、デバッガーなしで実行します。
SSL を使用するようにプロジェクトがまだ構成されていない場合、Visual Studio に次のダイアログが表示されます。
IIS Express SSL 証明書を信頼する場合は、[ はい ] を選択します。
次のダイアログが表示されます。
開発証明書を信頼することに同意する場合は、[ はい ] を選択します。
Firefox ブラウザーを信頼する方法については、 Firefox SEC_ERROR_INADEQUATE_KEY_USAGE証明書エラーに関する記事を参照してください。
Visual Studio で既定のブラウザーが起動し、https://localhost:<port>/swagger/index.html
にアクセスします。ここで、<port>
は、プロジェクト作成時に設定したランダムに選択されたポート番号になります。
Swagger ページ /swagger/index.html
が表示されます。
GET>試してみる>実行 を選択します。 ページに以下が表示されます。
- WeatherForecast API をテストする Curl コマンド。
- WeatherForecast API をテストする URL。
- 応答コード、本文、およびヘッダー。
- メディアの種類と、値とスキーマの例を含むドロップダウン リスト ボックス。
Swagger ページが表示されない場合は、 この GitHub の問題を参照してください。
Swagger は、Web API の有用なドキュメントやヘルプ ページを生成するために使用されます。 このチュートリアルでは、Swagger を使ってアプリをテストします。 Swagger の詳細については、Swagger /OpenAPI ASP.NET Core Web API のドキュメントを参照してください。
要求 URL をコピーしてブラウザーに貼り付けます。https://localhost:<port>/weatherforecast
次の例のような JSON が返されます。
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
モデル クラスの追加
モデルは、アプリが管理するデータを表すクラスのセットです。 このアプリのモデルは、TodoItem
クラスです。
- ソリューション エクスプローラー で、プロジェクトを右クリックします。 [ 追加>新しいフォルダー] を選択します。 フォルダーに「
Models
で行うことができます。 -
Models
フォルダーを右クリックし、[追加>Class] を選択します。 クラスに TodoItem という名前を付 け、[追加] を選択します。 - テンプレート コードを次のコードに置き換えます。
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Id
プロパティは、リレーショナル データベース内の一意のキーとして機能します。
モデル クラスはプロジェクト内のどこでも使用できますが、慣例により Models
フォルダーが使用されます。
データベース コンテキストの追加
データベース コンテキストは、データ モデルの Entity Framework 機能を調整するメイン クラスです。 このクラスは Microsoft.EntityFrameworkCore.DbContext クラスから派生させて作成します。
-
Models
フォルダーを右クリックし、[追加>Class] を選択します。 クラス に TodoContext という名前を 付け、[追加] をクリックします。
次のコードを入力します。
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
データベース コンテキストの登録
ASP.NET Core では、DB コンテキストなどのサービスを 依存関係挿入 (DI) コンテナーに登録する必要があります。 コンテナーは、コントローラーにサービスを提供します。
次の強調表示されているコードを使用して、Program.cs
を更新します。
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
上記のコードでは次の操作が行われます。
-
using
ディレクティブを追加します。 - DI コンテナーにデータベース コンテキストを追加します。
- データベース コンテキストがメモリ内データベースを使用することを指定します。
コントローラーのスキャフォールディング
Controllers
フォルダーを右クリックしします。[を選択します。
Entity Framework を使用して、アクションを含む API コントローラーを選択し、[追加] を選択します。
[Entity Framework を使用したアクションを含む API コントローラーの追加] ダイアログで、次の操作を行います。
- Model クラスで TodoItem (TodoApi.Models) を選択します。
- データ コンテキスト クラスで TodoContext (TodoApi.Models) を選択します。
- 追加を選択します。
スキャフォールディング操作が失敗した場合は、[ 追加 ] を選択して、もう一度スキャフォールディングを試みます。
生成されたコードでは次の操作が行われます。
- クラスを
[ApiController]
属性でマークします。 この属性は、コントローラーが Web API 要求に応答することを示します。 属性が有効にする特定の動作については、「 ASP.NET Core を使用した Web API の作成」を参照してください。 - DI を使用して、データベース コンテキスト (
TodoContext
) をコントローラーに挿入します。 データベース コンテキストは、コントローラー内の各 CRUD メソッドで使用されます。
ASP.NET Core テンプレートの対象は次のとおりです。
- ビューを含むコントローラーには、ルート テンプレートの
[action]
が含まれます。 - API コントローラーには、ルート テンプレートの
[action]
が含まれません。
[action]
トークンがルート テンプレートにない場合、アクション名 (メソッド名) はエンドポイントに含まれません。 つまり、アクションの関連付けられたメソッド名は一致するルートでは使用されません。
PostTodoItem 作成メソッドの更新
PostTodoItem
演算子を使用するために、 で return ステートメントを更新します。
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}
HTTP POST
属性が示すように、上記のコードは [HttpPost]
メソッドです。 このメソッドは、HTTP 要求の本文から TodoItem
の値を取得します。
詳細については、「 Http[Verb] 属性を使用した属性ルーティング」を参照してください。
CreatedAtAction メソッド:
- 成功した場合は 、HTTP 201 状態コード を返します。
HTTP 201
は、サーバーに新しいリソースを作成するHTTP POST
メソッドに対する標準の応答です。 -
Location ヘッダーを応答に追加します。
Location
ヘッダーは、新しく作成された to-do 項目の URI を指定します。 詳細については、「 10.2.2 201 Created」を参照してください。 -
GetTodoItem
アクションを参照してLocation
ヘッダーの URI を作成します。 C# のnameof
キーワードを使って、CreatedAtAction
呼び出しでアクション名をハードコーディングすることを回避しています。
PostTodoItem のテスト
Ctrl キーを押しながら F5 キーを押して、アプリを実行します。
Swagger ブラウザー ウィンドウで、 POST /api/TodoItems を選択し、[ 試してみる] を選択します。
要求本文の入力ウィンドウで、JSON を更新します。 たとえば、 にします。
{ "name": "walk dog", "isComplete": true }
[ 実行] を選択する
場所ヘッダー URI のテスト
前の POST では、Swagger UI は応答ヘッダーの下に 場所ヘッダー を表示 します。 たとえば、「 location: https://localhost:7260/api/TodoItems/1
」のように入力します。 場所ヘッダーには、作成されたリソースへの URI が表示されます。
場所ヘッダーをテストするには:
Swagger ブラウザー ウィンドウで、 GET /api/TodoItems/{id} を選択し、[ 試してみる] を選択します。
1
入力ボックスに「id
」と入力し、[実行] を選択します。
GET メソッドの確認
2 つの GET エンドポイントが実装されます。
GET /api/todoitems
GET /api/todoitems/{id}
前のセクションでは、/api/todoitems/{id}
ルートの例を示しました。
POST の指示に従って別の todo 項目を追加し、Swagger を使用して/api/todoitems
ルートをテストします。
このアプリではメモリ内データベースが使用されます。 アプリが停止して開始された場合、上記の GET 要求はどのようなデータも返しません。 データが返されない場合は、アプリに データを POST します。
ルーティングと URL パス
[HttpGet]
属性は、HTTP GET
要求に応答するメソッドを表します。 各メソッドの URL パスは次のように構成されます。
コントローラーの
Route
属性でテンプレート文字列を使用します。[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
[controller]
をコントローラーの名前 (慣例では "Controller" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsコントローラーであるため、コントローラー名は "TodoItems" です。 ASP.NET Core ルーティング では大文字と小文字が区別されません。[HttpGet]
属性にルート テンプレート (たとえば、[HttpGet("products")]
) がある場合は、それをパスに追加します。 このサンプルではテンプレートを使用しません。 詳細については、「 Http[Verb] 属性を使用した属性ルーティング」を参照してください。
次の GetTodoItem
メソッドで、"{id}"
は To Do アイテムの一意識別子に使用するプレースホルダーの変数です。
GetTodoItem
が呼び出されると、その "{id}"
パラメーター内のメソッドに URL の id
の値が指定されます。
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
戻り値
GetTodoItems
メソッドと GetTodoItem
メソッドの戻り値の型は ActionResult<T> 型です。 ASP.NET Core は、オブジェクトを JSON に自動的にシリアル化し、応答メッセージの本文に JSON を書き込みます。 この戻り値の型の応答コードは 200 OK です。ハンドルされない例外がないと仮定します。 ハンドルされない例外は 5xx エラーに変換されます。
ActionResult
戻り値の型は、幅広い範囲の HTTP 状態コードを表すことができます。 たとえば、GetTodoItem
は、次の 2 つの異なる状態値を返す可能性があります。
- 要求された ID と一致する項目がない場合、メソッドは 404 状態NotFound エラー コードを返します。
- それ以外の場合、メソッドは JSON 応答本文で 200 を返します。 戻り値が
item
の場合、HTTP 200
応答が返されます。
PutTodoItem メソッド
PutTodoItem
メソッドを検証します。
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
は PostTodoItem
と似ていますが、HTTP PUT
を使用します。 応答は 204 (コンテンツなし) です。 HTTP 仕様に従って、PUT
要求では、変更だけでなく、更新されたエンティティ全体を送信するようクライアントに求めます。 部分的な更新をサポートするには、 HTTP PATCH を使用します。
PutTodoItem メソッドのテスト
このサンプルでは、アプリを起動するたびに開始することが必要なメモリ内データベースが使われています。 PUT 呼び出しを実行する前に、データベース内にアイテムが存在している必要があります。 GET を呼び出して、PUT 呼び出しを実行する前にデータベース内にアイテムが確実に存在していることを確認します。
Swagger UI を使用して、PUT ボタンを使用して Id = 1 の TodoItem
を更新し、その名前を "feed fish"
に設定します。 応答は HTTP 204 No Content
であることに注意してください。
DeleteTodoItem メソッド
DeleteTodoItem
メソッドを検証します。
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
DeleteTodoItem メソッドのテスト
Swagger UI を使用して、Id = 1 の TodoItem
を削除します。 応答は HTTP 204 No Content
であることに注意してください。
他のツールでテストする
Web API のテストには、他にも使用できるツールが多数あります。次に例を示します。
- Visual Studio エンドポイント エクスプローラーと .http ファイル
- http-repl
-
curl。 Swagger は
curl
を使い、送信されたcurl
コマンドを表示します。 - バイオリン弾き
詳細については、次を参照してください。
過剰な投稿を防止する
現在、サンプル アプリでは TodoItem
オブジェクト全体が公開されています。 通常、運用環境のアプリでは、モデルのサブセットを使用して入力されるデータおよび返されるデータが制限されています。 その背景には複数の理由があり、セキュリティは主なものです。 モデルのサブセットは、通常、データ転送オブジェクト (DTO)、入力モデル、またはビュー モデルと呼ばれます。 このチュートリアルでは DTO を使用します。
DTO は次の目的で使用できます。
- 過剰な投稿を防止する。
- クライアントが表示しないことになっているプロパティを非表示にする。
- ペイロード サイズを減らすために、いくつかのプロパティを省略する。
- 入れ子になったオブジェクトを含むオブジェクト グラフをフラット化する。 フラット化されたオブジェクト グラフは、クライアントにとってより便利になる可能性があります。
DTO のアプローチを実演するために、TodoItem
クラスを更新して、シークレット フィールドを含めます。
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
シークレット フィールドは、このアプリでは非表示にする必要がありますが、管理アプリの場合は公開することを選択できます。
シークレット フィールドを投稿および取得できることを確認します。
次のように DTO モデルを作成します。
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemsController
を使用するように TodoItemDTO
を更新します。
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
シークレット フィールドを投稿または取得できないことを確認します。
JavaScript を使用した Web API の呼び出し
「 チュートリアル: JavaScript を使用して ASP.NET Core Web API を呼び出す」を参照してください。
Web API ビデオ シリーズ
ビデオ: 初心者向けシリーズ:Web API を参照してください。
エンタープライズ Web アプリのパターン
信頼性が高く、セキュリティで保護され、パフォーマンスが高く、テスト可能でスケーラブルな ASP.NET Core アプリの作成に関するガイダンスについては、 エンタープライズ Web アプリのパターンに関するページを参照してください。 パターンを実装する完全な運用品質のサンプル Web アプリを使用できます。
Web API に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- フェデレーション ゲートウェイ
重要
Duende ソフトウェアでは、DuendeIdentity Server の運用環境での使用に対するライセンス料金の支払いが必要になる場合があります。 詳細については、「 .NET 5 の ASP.NET Core から .NET 6 への移行」を参照してください。
詳細については、 Duende Identity Server のドキュメント (Duende Software Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイの詳細については、「 クイック スタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロードする方法を参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使用して Web API を作成する
- チュートリアル: ASP.NET Core を使用して最小限の API を作成する
- Swagger/OpenAPI を使用した ASP.NET Core Web API ドキュメント
- Razor ASP.NET Core の Entity Framework Core を含むページ - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- ASP.NET Core アプリを Azure App Service にデプロイする
- ASP.NET Core のホストとデプロイ
- ASP.NET Core を使用して Web API を作成する
ASP.NET Core