チュートリアル: ASP.NET Core で Web API を作成する
作成者: Rick Anderson および Kirk Larkin
注意
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 7 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 7 バージョンを参照してください。
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小 API とコントローラー ベースの API の選択に関するヘルプについては、API の概要に関する記事をご覧ください。 最小 API の作成に関するチュートリアルについては、「チュートリアル: ASP.NET Core を使って最小 API を作成する」をご覧ください。
概要
このチュートリアルでは、次の API を作成します。
API | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | None | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | None | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | None |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | None | None |
次の図は、アプリのデザインを示しています。
必須コンポーネント
Visual Studio 2022 Preview と ASP.NET および Web 開発ワークロード。
Web プロジェクトの作成
- [ファイル] メニューで [新規作成]>[プロジェクト] の順に選択します。
- 検索ボックスに「Web API」と入力します。
- [ASP.NET Core Web API] テンプレートを選択し、 [次へ] を選択します。
- [新しいプロジェクトの構成] ダイアログで、プロジェクトに TodoApi という名前を付けて、[次へ] を選択します。
- [追加情報] ダイアログで、次を行います。
- [フレームワーク] が .NET 8.0 (プレビュー) であることを確認します。
- [コントローラーを使用する (最小限の API を使用する場合はオフにします)] チェック ボックスがオンになっていることを確認します。
- [Enable OpenAPI support] (OpenAPI サポートを有効にする) のチェックボックスがオンになっていることを確認します。
- [作成] を選択します。
NuGet パッケージの追加
このチュートリアルで使うデータベースをサポートするには、NuGet パッケージを追加する必要があります。
- [ツール] メニューで [NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] の順に選択します。
- [参照] タブを選択します。
- [プレリリースを含める] チェック ボックスをオンにします。
- 検索ボックスに「Microsoft.EntityFrameworkCore.InMemory」と入力し、
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [プロジェクト] チェックボックスをオンにして、[インストール] を選択します。
メモ
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトをテストする
プロジェクト テンプレートにより、Swagger をサポートする 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
が表示されます。 [取得]>[試してみる]>[実行] を選択します。 ページに以下が表示されます。
- 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
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「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
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「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 コントローラー] ダイアログで次を実行します。
- モデル クラスで [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 作成メソッドの更新
nameof 演算子を使用するために、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);
}
[HttpPost]
属性が示すように、上記のコードは HTTP POST
メソッドです。 このメソッドは、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}] を選択し、次に [試してみる] を選択します。
id
入力ボックスに1
を入力し、[実行] を選択します。
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" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsController なので、コントローラー名は "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 (No Content) となります。 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 Endpoints Explorer と .http ファイル
- http-repl
- Postman
- curl。 Swagger は
curl
を使い、送信されたcurl
コマンドを表示します。 - Fiddler
詳細については次を参照してください:
- 最小 API のチュートリアル: .http ファイルと Endpoints Explorer を使ってテストする
- Postman を使用して API をテストする
http-repl
を使用して 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; }
}
}
シークレット フィールドは、このアプリでは非表示にする必要がありますが、管理アプリの場合は公開することを選択できます。
シークレット フィールドを投稿および取得できることを確認します。
次のように DTO モデルを作成します。
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemDTO
を使用するように TodoItemsController
を更新します。
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 アプリ パターン
.NET 用の信頼性の高い Web アプリ パターンYouTube のビデオと記事を参照して、ゼロからでも既存のアプリをリファクタリングしても、信頼性が高く、パフォーマンスが高く、テスト可能で、コスト効率が高く、スケーラブルな ASP.NET Core アプリを作成する方法に関するガイダンスを参照してください。
Web API に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイについては、「クイックスタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロード方法に関するページを参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使って Web API を作成する
- チュートリアル: ASP.NET Core を使って最小 API を作成する
- Swagger/OpenAPI を使用する ASP.NET Core Web API のドキュメント
- RazorASP.NET Core での Entity Framework Core を使用した Pages - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- Azure App Service に ASP.NET Core アプリを展開する
- 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 アイテムを取得します。 | None | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | None | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | None |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | None | None |
次の図は、アプリのデザインを示しています。
必須コンポーネント
Visual Studio 2022 と ASP.NET と Web 開発ワークロード。
Web プロジェクトの作成
- [ファイル] メニューで [新規作成]>[プロジェクト] の順に選択します。
- 検索ボックスに「Web API」と入力します。
- [ASP.NET Core Web API] テンプレートを選択し、 [次へ] を選択します。
- [新しいプロジェクトの構成] ダイアログで、プロジェクトに TodoApi という名前を付けて、[次へ] を選択します。
- [追加情報] ダイアログで、次を行います。
- [フレームワーク] が .NET 7.0 (またはそれ以降) であることを確認します。
- [コントローラーを使用する (最小限の API を使用する場合はオフにします)] チェック ボックスがオンになっていることを確認します。
- 作成 を選択します。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトをテストする
プロジェクト テンプレートにより、Swagger をサポートする 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
が表示されます。 [取得]>[試してみる]>[実行] を選択します。 ページに以下が表示されます。
- WeatherForecast API をテストするための Curl コマンド。
- WeatherForecast API をテストする URL。
- 応答コード、本文、およびヘッダー。
- メディアの種類と、値とスキーマの例を含むドロップダウン リスト ボックス。
Swagger ページが表示されない場合は、こちらの GitHub イシューを参照してください。
Swagger は、Web API の有用なドキュメントやヘルプ ページを生成するために使用されます。 このチュートリアルでは、Web API の作成について説明します。 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
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「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 クラスから派生させて作成します。
NuGet パッケージを追加する
- [ツール] メニューで [NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] の順に選択します。
- [参照] タブを選択し、検索ボックスに「
Microsoft.EntityFrameworkCore.InMemory
」と入力します。 - 左側のウィンドウで
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [プロジェクト] チェックボックスをオンにして、 [インストール] を選択します。
TodoContext データベースコンテキストの追加
Models
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「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 コントローラー] ダイアログで次を実行します。
- モデル クラスで [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 作成メソッドの更新
nameof 演算子を使用するために、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);
}
[HttpPost]
属性が示すように、上記のコードは HTTP POST
メソッドです。 このメソッドは、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}] を選択し、次に [試してみる] を選択します。
id
入力ボックスに1
を入力し、[実行] を選択します。
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" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsController なので、コントローラー名は "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 (No Content) となります。 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
であることに注意してください。
http-repl、Postman、または curl を使用してテストする
http-repl、Postman、curl は、API のテストによく使用されます。 Swagger は curl
を使用し、送信された curl
コマンドを表示します。
これらのツールの手順については、次のリンクを参照してください。
http-repl
の詳細については、「HttpRepl を使用して 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; }
}
}
シークレット フィールドは、このアプリでは非表示にする必要がありますが、管理アプリの場合は公開することを選択できます。
シークレット フィールドを投稿および取得できることを確認します。
次のように DTO モデルを作成します。
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemDTO
を使用するように TodoItemsController
を更新します。
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 アプリ パターン
.NET 用の信頼性の高い Web アプリ パターンYouTube のビデオと記事を参照して、ゼロからでも既存のアプリをリファクタリングしても、信頼性が高く、パフォーマンスが高く、テスト可能で、コスト効率が高く、スケーラブルな ASP.NET Core アプリを作成する方法に関するガイダンスを参照してください。
Web API に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイについては、「クイックスタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロード方法に関するページを参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使って Web API を作成する
- チュートリアル: ASP.NET Core を使って最小 API を作成する
- Swagger/OpenAPI を使用する ASP.NET Core Web API のドキュメント
- RazorASP.NET Core での Entity Framework Core を使用した Pages - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- Azure App Service に ASP.NET Core アプリを展開する
- ASP.NET Core のホストと展開
- ASP.NET Core で Web API を作成する
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小 API とコントローラー ベースの API の選択に関するヘルプについては、API の概要に関する記事をご覧ください。 最小 API の作成に関するチュートリアルについては、「チュートリアル: ASP.NET Core を使って最小 API を作成する」をご覧ください。
このチュートリアルでは、次の作業を行う方法について説明します。
- Web API プロジェクトを作成する。
- モデル クラスとデータベース コンテキストを追加する。
- CRUD メソッドを使用してコントローラーのスキャフォールディング。
- ルーティング、URL パス、戻り値を構成する。
- http-repl で Web API を呼び出す。
最後に、データベースに格納されている "To Do" アイテムを管理できる Web API が作成されます。
概要
このチュートリアルでは、次の API を作成します。
API | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | None | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | None | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | None |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | None | None |
次の図は、アプリのデザインを示しています。
必須コンポーネント
- Visual Studio 2022 と ASP.NET と Web 開発ワークロード。
Web プロジェクトの作成
- [ファイル] メニューで [新規作成]>[プロジェクト] の順に選択します。
- 検索ボックスに「Web API」と入力します。
- [ASP.NET Core Web API] テンプレートを選択し、 [次へ] を選択します。
- [新しいプロジェクトの構成] ダイアログで、プロジェクトに TodoApi という名前を付けて、[次へ] を選択します。
- [追加情報] ダイアログで、次を行います。
- [フレームワーク] が [.NET 6.0 (長期的なサポート)] になっていることを確認します。
- [コントローラーを使用する (最小限の API を使用する場合はオフにします)] チェック ボックスがオンになっていることを確認します。
- 作成 を選択します。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトをテストする
プロジェクト テンプレートにより、Swagger をサポートする 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
が表示されます。 [取得]>[試してみる]>[実行] を選択します。 ページに以下が表示されます。
- WeatherForecast API をテストするための Curl コマンド。
- WeatherForecast API をテストする URL。
- 応答コード、本文、およびヘッダー。
- メディアの種類と、値とスキーマの例を含むドロップダウン リスト ボックス。
Swagger ページが表示されない場合は、こちらの GitHub イシューを参照してください。
Swagger は、Web API の有用なドキュメントやヘルプ ページを生成するために使用されます。 このチュートリアルでは、Web API の作成について説明します。 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"
}
]
launchUrl を更新する
Properties\launchSettings.json で、launchUrl
を "swagger"
から "api/todoitems"
に更新します。
"launchUrl": "api/todoitems",
Swagger が削除されるため、上記のマークアップにより、開始される URL が、次のセクションで追加されるコントローラーの GET メソッドに変更されます。
モデル クラスの追加
モデルは、アプリが管理するデータを表すクラスのセットです。 このアプリのモデルは、単一の TodoItem
クラスです。
ソリューション エクスプローラーで、プロジェクトを右クリックします。 [追加]>[新しいフォルダー] の順に選択します。 フォルダーに「
Models
で行うことができます。Models
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「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 クラスから派生させて作成します。
NuGet パッケージを追加する
- [ツール] メニューで [NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] の順に選択します。
- [参照] タブを選択し、検索ボックスに「
Microsoft.EntityFrameworkCore.InMemory
」と入力します。 - 左側のウィンドウで
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [プロジェクト] チェックボックスをオンにして、 [インストール] を選択します。
TodoContext データベースコンテキストの追加
Models
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「TodoContext」という名前を付け、 [追加] をクリックします。
次のコードを入力します。
using Microsoft.EntityFrameworkCore; using System.Diagnostics.CodeAnalysis; 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);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
//builder.Services.AddSwaggerGen(c =>
//{
// c.SwaggerDoc("v1", new() { Title = "TodoApi", Version = "v1" });
//});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseSwagger();
//app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1"));
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
上記のコードでは次の操作が行われます。
- Swagger 呼び出しを削除します。
- 不要な
using
ディレクティブを削除します。 - DI コンテナーにデータベース コンテキストを追加します。
- データベース コンテキストがメモリ内データベースを使用することを指定します。
コントローラーのスキャフォールディング
Controllers フォルダーを右クリックします。
[追加]>[スキャフォールディングされた新しい項目] を選択します。
[Entity Framework を使用したアクションがある API コントローラー] を選択してから、 [追加] を選択します。
[Entity Framework を使用したアクションがある API コントローラー] ダイアログで次を実行します。
- モデル クラスで [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 作成メソッドの更新
nameof 演算子を使用するために、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);
}
[HttpPost]
属性が示すように、上記のコードは HTTP POST メソッドです。 このメソッドは、HTTP 要求の本文から To Do アイテムの値を取得します。
詳細については、「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
呼び出しでアクション名をハードコーディングすることを回避しています。
http-repl のインストール
このチュートリアルでは、http-repl を使用して Web API をテストします。
コマンド プロンプトで次のコマンドを実行します。
dotnet tool install -g Microsoft.dotnet-httprepl
メモ
既定では、インストールする .NET バイナリのアーキテクチャは、現在実行中の OS アーキテクチャを表します。 別の OS アーキテクチャを指定するには、「dotnet tool install, --arch option」を参照してください。 詳細については、GitHub イシュー dotnet/AspNetCore.Docs #29262 を参照してください。
.NET 6.0 SDK またはランタイムがインストールされていない場合は、.NET 6.0 ランタイムをインストールします。
PostTodoItem のテスト
Ctrl キーを押しながら F5 キーを押して、アプリを実行します。
新しいターミナル ウィンドウを開き、次のコマンドを実行します。 アプリで別のポート番号を使用する場合は、httprepl コマンドの 5001 をお使いのポート番号に置き換えてください。
httprepl https://localhost:5001/api/todoitems post -h Content-Type=application/json -c "{"name":"walk dog","isComplete":true}"
このコマンドの出力例は次のとおりです。
HTTP/1.1 201 Created Content-Type: application/json; charset=utf-8 Date: Tue, 07 Sep 2021 20:39:47 GMT Location: https://localhost:5001/api/TodoItems/1 Server: Kestrel Transfer-Encoding: chunked { "id": 1, "name": "walk dog", "isComplete": true }
場所ヘッダー URI のテスト
場所ヘッダーをテストするには、それをコピーして httprepl get
コマンドに貼り付けます。
次の例では、httprepl セッション内であることを前提としています。 前の httprepl セッションを終了した場合は、次のコマンドで connect
を httprepl
に置き換えてください。
connect https://localhost:5001/api/todoitems/1
get
このコマンドの出力例は次のとおりです。
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Tue, 07 Sep 2021 20:48:10 GMT
Server: Kestrel
Transfer-Encoding: chunked
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
GET メソッドの確認
2 つの GET エンドポイントが実装されます。
GET /api/todoitems
GET /api/todoitems/{id}
/api/todoitems/{id}
ルートの例は既に確認しました。 /api/todoitems
ルートをテストします。
connect https://localhost:5001/api/todoitems
get
このコマンドの出力例は次のとおりです。
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Tue, 07 Sep 2021 20:59:21 GMT
Server: Kestrel
Transfer-Encoding: chunked
[
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
]
今回返される JSON は 1 つのアイテムの配列です。
このアプリではメモリ内データベースが使用されます。 アプリが停止して開始された場合、上記の GET 要求はデータを返しません。 データが返されない場合は、アプリにデータを POST します。
ルーティングと URL パス
[HttpGet]
属性は、HTTP GET 要求に応答するメソッドを表します。 各メソッドの URL パスは次のように構成されます。
コントローラーの
Route
属性でテンプレート文字列を使用します。[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
[controller]
をコントローラーの名前 (慣例では "Controller" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsController なので、コントローラー名は "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 (No Content) となります。 HTTP 仕様に従って、PUT 要求では、変更だけでなく、更新されたエンティティ全体を送信するようクライアントに求めます。 部分的な更新をサポートするには、HTTP PATCH を使用します。
次のセクションの PutTodoItem
呼び出しでエラーが発生した場合、GET
を呼び出してデータベース内にアイテムがあることを確認してください。
PutTodoItem メソッドのテスト
このサンプルでは、アプリを起動するたびに開始することが必要なメモリ内データベースが使われています。 PUT 呼び出しを実行する前に、データベース内にアイテムが存在している必要があります。 GET を呼び出して、PUT 呼び出しを実行する前にデータベース内にアイテムが確実に存在していることを確認します。
Id = 1 の To Do アイテムを更新し、その名前を "feed fish"
に設定します。
connect https://localhost:5001/api/todoitems/1
put -h Content-Type=application/json -c "{"id":1,"name":"feed fish","isComplete":true}"
このコマンドの出力例は次のとおりです。
HTTP/1.1 204 No Content
Date: Tue, 07 Sep 2021 21:20:47 GMT
Server: Kestrel
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 の To Do アイテムを削除します。
connect https://localhost:5001/api/todoitems/1
delete
このコマンドの出力例は次のとおりです。
HTTP/1.1 204 No Content
Date: Tue, 07 Sep 2021 21:43:00 GMT
Server: Kestrel
過剰な投稿を防止する
現在、サンプル アプリでは 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; }
}
}
TodoItemDTO
を使用するように TodoItemsController
を更新します。
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
[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);
}
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// 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 API に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイについては、「クイックスタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロード方法に関するページを参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使って Web API を作成する
- チュートリアル: ASP.NET Core を使って最小 API を作成する
- Swagger/OpenAPI を使用する ASP.NET Core Web API のドキュメント
- RazorASP.NET Core での Entity Framework Core を使用した Pages - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- Azure App Service に ASP.NET Core アプリを展開する
- ASP.NET Core のホストと展開
- ASP.NET Core で Web API を作成する
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小 API とコントローラー ベースの API の選択に関するヘルプについては、API の概要に関する記事をご覧ください。 最小 API の作成に関するチュートリアルについては、「チュートリアル: ASP.NET Core を使って最小 API を作成する」をご覧ください。
このチュートリアルでは、次の作業を行う方法について説明します。
- Web API プロジェクトを作成する。
- モデル クラスとデータベース コンテキストを追加する。
- CRUD メソッドを使用してコントローラーのスキャフォールディング。
- ルーティング、URL パス、戻り値を構成する。
- Postman で Web API を呼び出す。
最後に、データベースに格納されている "To Do" アイテムを管理できる Web API が作成されます。
概要
このチュートリアルでは、次の API を作成します。
API | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | None | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | None | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | None |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | None | None |
次の図は、アプリのデザインを示しています。
必須コンポーネント
- ASP.NET および Web 開発ワークロードを含む Visual Studio 2019 16.8 以降
- .NET 5.0 SDK
Web プロジェクトの作成
- [ファイル] メニューで [新規作成]>[プロジェクト] の順に選択します。
- [ASP.NET Core Web API] テンプレートを選択し、 [次へ] をクリックします。
- プロジェクトに「TodoApi」という名前を付け、 [作成] をクリックします。
- [新しい ASP.NET Core Web アプリケーションを作成する] ダイアログで、 [.NET Core] と [ASP.NET Core 5.0] が選択されていることを確認します。 API テンプレートを選択し、[作成] をクリックします。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
プロジェクトをテストする
プロジェクト テンプレートにより、Swagger をサポートする WeatherForecast
API が作成されます。
Ctrl + F5 キーを押して、デバッガーなしで実行します。
SSL を使用するようにプロジェクトがまだ構成されていない場合、Visual Studio に次のダイアログが表示されます。
IIS Express SSL 証明書を信頼する場合、[はい] を選択します。
次のダイアログが表示されます。
開発証明書を信頼することに同意する場合は、[はい] を選択します。
Firefox ブラウザーを信頼する方法の詳細については、「Firefox SEC_ERROR_INADEQUATE_KEY_USAGE 証明書エラー」を参照してください。
Visual Studio により、以下が起動されます。
- IIS Express Web サーバー。
- 既定のブラウザーです。
https://localhost:<port>/swagger/index.html
に移動します。<port>
はランダムに選択されるポート番号です。
Swagger ページ /swagger/index.html
が表示されます。 [取得]>[試してみる]>[実行] を選択します。 ページに以下が表示されます。
- WeatherForecast API をテストするための Curl コマンド。
- WeatherForecast API をテストする URL。
- 応答コード、本文、およびヘッダー。
- メディアの種類と、値とスキーマの例を含むドロップ ダウン リスト ボックス。
Swagger ページが表示されない場合は、こちらの GitHub イシューを参照してください。
Swagger は、Web API の有用なドキュメントやヘルプ ページを生成するために使用されます。 このチュートリアルでは、Web API の作成について説明します。 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"
}
]
launchUrl を更新する
Properties\launchSettings.json で、launchUrl
を "swagger"
から "api/todoitems"
に更新します。
"launchUrl": "api/todoitems",
Swagger が削除されるため、上記のマークアップにより、開始される URL が、次のセクションで追加されるコントローラーの GET メソッドに変更されます。
モデル クラスの追加
モデルは、アプリが管理するデータを表すクラスのセットです。 このアプリのモデルは、単一の TodoItem
クラスです。
ソリューション エクスプローラーで、プロジェクトを右クリックします。 [追加]>[新しいフォルダー] の順に選択します。 フォルダーに「
Models
で行うことができます。Models
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「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 クラスから派生させて作成します。
NuGet パッケージを追加する
- [ツール] メニューで [NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] の順に選択します。
- [参照] タブを選択し、検索ボックスに「
Microsoft.EntityFrameworkCore.InMemory
」と入力します。 - 左側のウィンドウで
Microsoft.EntityFrameworkCore.InMemory
を選択します。 - 右側のウィンドウで [プロジェクト] チェックボックスをオンにして、 [インストール] を選択します。
TodoContext データベースコンテキストの追加
Models
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「TodoContext」という名前を付け、 [追加] をクリックします。
次のコードを入力します。
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }
データベース コンテキストの登録
ASP.NET Core で、サービス (DB コンテキストなど) を依存関係の挿入 (DI)コンテナーに登録する必要があります。 コンテナーは、コントローラーにサービスを提供します。
次のコードを使用して Startup.cs
を更新します。
// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
//services.AddSwaggerGen(c =>
//{
// c.SwaggerDoc("v1", new OpenApiInfo { Title = "TodoApi", Version = "v1" });
//});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseSwagger();
//app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
上記のコードでは次の操作が行われます。
- Swagger 呼び出しを削除します。
- 不要な
using
宣言を削除します。 - DI コンテナーにデータベース コンテキストを追加します。
- データベース コンテキストがメモリ内データベースを使用することを指定します。
コントローラーのスキャフォールディング
Controllers フォルダーを右クリックします。
[追加]>[スキャフォールディングされた新しい項目] を選択します。
[Entity Framework を使用したアクションがある API コントローラー] を選択してから、 [追加] を選択します。
[Entity Framework を使用したアクションがある API コントローラー] ダイアログで次を実行します。
- モデル クラスで [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 作成メソッドの更新
nameof 演算子を使用するために、PostTodoItem
で return ステートメントを更新します。
// POST: api/TodoItems
[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);
}
[HttpPost]
属性が示すように、上記のコードは HTTP POST メソッドです。 このメソッドは、HTTP 要求の本文から To Do アイテムの値を取得します。
詳細については、「Http[Verb] 属性を使用する属性ルーティング」を参照してください。
CreatedAtAction メソッド:
- 成功すると、HTTP 201 状態コードが返されます。 HTTP 201 は、サーバーに新しいリソースを作成する HTTP POST メソッドに対する標準の応答です。
- 応答に Location ヘッダーが追加されます。
Location
ヘッダーでは、新しく作成された To Do アイテムの URI が指定されます。 詳細については、「201 Created」を参照してください。 GetTodoItem
アクションを参照してLocation
ヘッダーの URI を作成します。 C# のnameof
キーワードを使って、CreatedAtAction
呼び出しでアクション名をハードコーディングすることを回避しています。
Postman のインストール
このチュートリアルでは、Postman を使用して Web API をテストします。
- Postman をインストールします。
- Web アプリを起動します。
- Postman を起動します。
- [SSL 証明書の確認] を無効にします。
- Windows 用 Postman: [ファイル]>[設定] ([全般] タブ) の順に選択し、[SSL 証明書の確認] を無効にします。
- macOS 用 Postman: [Postman]>[設定] ([全般] タブ) の順に選択し、[SSL 証明書の確認] を無効にします。
警告
コントローラーをテストした後、SSL 証明書の検証を再度有効にします。
Postman を使用した PostTodoItem のテスト
新しい要求を作成します。
HTTP メソッドを
POST
に設定します。URI を
https://localhost:<port>/api/todoitems
に設定します。 たとえば、「https://localhost:5001/api/todoitems
」のように入力します。[Body] タブを選択します。
[raw] ラジオ ボタンを選択します。
型を [JSON (application/json)] に設定します。
要求本文に、To Do アイテムの JSON を入力します。
{ "name":"walk dog", "isComplete":true }
[Send] を選択します。
場所ヘッダー URI のテスト
場所ヘッダー URI は、ブラウザーでテストできます。 場所ヘッダー URI をコピーしてブラウザーに貼り付けます。
Postman でテストするには:
[Response] ウィンドウで、 [Headers] タブを選択します。
[Location] ヘッダー値をコピーします。
HTTP メソッドを
GET
に設定します。URI を
https://localhost:<port>/api/todoitems/1
に設定します。 たとえば、「https://localhost:5001/api/todoitems/1
」のように入力します。[Send] を選択します。
GET メソッドの確認
2 つの GET エンドポイントが実装されます。
GET /api/todoitems
GET /api/todoitems/{id}
ブラウザーまたは Postman から 2 つのエンドポイントを呼び出すことによって、アプリをテストします。 次に例を示します。
https://localhost:5001/api/todoitems
https://localhost:5001/api/todoitems/1
GetTodoItems
への呼び出しによって、次のような応答が生成されます。
[
{
"id": 1,
"name": "Item1",
"isComplete": false
}
]
Postman を使用して Get をテストする
- 新しい要求を作成します。
- HTTP メソッドを GET に設定します。
- 要求 URI を
https://localhost:<port>/api/todoitems
に設定します。 たとえば、https://localhost:5001/api/todoitems
のようにします。 - Postman で [Two pane view] を設定します。
- [Send] を選択します。
このアプリではメモリ内データベースが使用されます。 アプリが停止して開始された場合、上記の GET 要求はデータを返しません。 データが返されない場合は、アプリにデータを POST します。
ルーティングと URL パス
[HttpGet]
属性は、HTTP GET 要求に応答するメソッドを表します。 各メソッドの URL パスは次のように構成されます。
コントローラーの
Route
属性でテンプレート文字列を使用します。[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }
[controller]
をコントローラーの名前 (慣例では "Controller" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsController なので、コントローラー名は "TodoItems" です。 ASP.NET Core のルーティングでは、大文字と小文字が区別されません。[HttpGet]
属性にルート テンプレート (たとえば、[HttpGet("products")]
) がある場合は、それをパスに追加します。 このサンプルではテンプレートを使用しません。 詳細については、「Http[Verb] 属性を使用する属性ルーティング」を参照してください。
次の GetTodoItem
メソッドで、"{id}"
は To Do アイテムの一意識別子に使用するプレースホルダーの変数です。 GetTodoItem
が呼び出されると、その id
パラメーター内のメソッドに URL の "{id}"
の値が指定されます。
// GET: api/TodoItems/5
[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
メソッドを検証します。
// PUT: api/TodoItems/5
[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 (No Content) となります。 HTTP 仕様に従って、PUT 要求では、変更だけでなく、更新されたエンティティ全体を送信するようクライアントに求めます。 部分的な更新をサポートするには、HTTP PATCH を使用します。
PutTodoItem
呼び出しでエラーが発生した場合、GET
を呼び出してデータベース内にアイテムがあることを確認してください。
PutTodoItem メソッドのテスト
このサンプルでは、アプリを起動するたびに開始することが必要なメモリ内データベースが使われています。 PUT 呼び出しを実行する前に、データベース内にアイテムが存在している必要があります。 GET を呼び出して、PUT 呼び出しを実行する前にデータベース内にアイテムが確実に存在していることを確認します。
Id = 1 の To Do アイテムを更新し、その名前を "feed fish"
に設定します。
{
"Id":1,
"name":"feed fish",
"isComplete":true
}
次の図は、Postman の更新を示しています。
DeleteTodoItem メソッド
DeleteTodoItem
メソッドを検証します。
// 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();
}
DeleteTodoItem メソッドのテスト
Postman を使用して、To Do アイテムを削除します。
- メソッドを
DELETE
に設定します。 - 削除するオブジェクトの URI (たとえば、
https://localhost:5001/api/todoitems/1
) を設定します。 - [Send] を選択します。
過剰な投稿を防止する
現在、サンプル アプリでは 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 モデルを作成します。
public class TodoItemDTO
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemDTO
を使用するように TodoItemsController
を更新します。
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
[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);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
[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) =>
_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 に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイについては、「クイックスタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロード方法に関するページを参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使って Web API を作成する
- チュートリアル: ASP.NET Core を使って最小 API を作成する
- Swagger/OpenAPI を使用する ASP.NET Core Web API のドキュメント
- RazorASP.NET Core での Entity Framework Core を使用した Pages - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- Azure App Service に ASP.NET Core アプリを展開する
- ASP.NET Core のホストと展開
- ASP.NET Core で Web API を作成する
このチュートリアルでは、データベースを使用するコントローラー ベースの Web API の構築の基本について説明します。 ASP.NET Core で API を作成するもう 1 つの方法は、"最小 API" を作成することです。 最小 API とコントローラー ベースの API の選択に関するヘルプについては、API の概要に関する記事をご覧ください。 最小 API の作成に関するチュートリアルについては、「チュートリアル: ASP.NET Core を使って最小 API を作成する」をご覧ください。
このチュートリアルでは、次の作業を行う方法について説明します。
- Web API プロジェクトを作成する。
- モデル クラスとデータベース コンテキストを追加する。
- CRUD メソッドを使用してコントローラーのスキャフォールディング。
- ルーティング、URL パス、戻り値を構成する。
- Postman で Web API を呼び出す。
最後に、データベースに格納されている "To Do" アイテムを管理できる Web API が作成されます。
概要
このチュートリアルでは、次の API を作成します。
API | 説明 | 要求本文 | 応答本文 |
---|---|---|---|
GET /api/todoitems |
すべての To Do アイテムを取得します。 | None | To Do アイテムの配列 |
GET /api/todoitems/{id} |
ID でアイテムを取得します。 | None | To Do アイテム |
POST /api/todoitems |
新しいアイテムを追加します。 | To Do アイテム | To Do アイテム |
PUT /api/todoitems/{id} |
既存のアイテムを更新します。 | To Do アイテム | None |
DELETE /api/todoitems/{id} |
アイテムを削除します。 | None | None |
次の図は、アプリのデザインを示しています。
必須コンポーネント
ASP.NET および Web 開発ワークロードを含む Visual Studio 2019 16.4 以降
Web プロジェクトの作成
- [ファイル] メニューで [新規作成]>[プロジェクト] の順に選択します。
- [ASP.NET Core Web アプリケーション] テンプレートを選択して、 [次へ] をクリックします。
- プロジェクトに「TodoApi」という名前を付け、 [作成] をクリックします。
- [新しい ASP.NET Core Web アプリケーションを作成する] ダイアログで、 [.NET Core] と [ASP.NET Core 3.1] が選択されていることを確認します。 API テンプレートを選択し、[作成] をクリックします。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
API のテスト
プロジェクト テンプレートによって WeatherForecast
API が作成されます。 ブラウザーから Get
メソッドを呼び出して、アプリをテストします。
Ctrl キーを押しながら F5 キーを押して、アプリを実行します。 Visual Studio でブラウザーが起動し、https://localhost:<port>/weatherforecast
にアクセスします。ここで、<port>
はランダムに選択されたポート番号になります。
IIS Express 証明書を信頼するかどうかを確認するダイアログ ボックスが表示された場合は、 [はい] を選択します。 次に表示される [セキュリティ警告] ダイアログ ボックスで、 [はい] を選択します。
次のような 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
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「TodoItem」という名前を付け、 [追加] を選択します。テンプレート コードを次のコードに置き換えます。
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
クラスから派生させて作成します。
NuGet パッケージを追加する
- [ツール] メニューで [NuGet パッケージ マネージャー] > [ソリューションの NuGet パッケージの管理] の順に選択します。
- [参照] タブを選択し、検索ボックスに「Microsoft.EntityFrameworkCore.InMemory」と入力します。
- 左側のウィンドウで、 [Microsoft.EntityFrameworkCore.InMemory] を選択します。
- 右側のウィンドウで [プロジェクト] チェックボックスをオンにして、[インストール] を選択します。
TodoContext データベースコンテキストの追加
Models
フォルダーを右クリックして、[追加]>[クラス] の順に選択します。 クラスに「TodoContext」という名前を付け、 [追加] をクリックします。
次のコードを入力します。
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }
データベース コンテキストの登録
ASP.NET Core で、サービス (DB コンテキストなど) を依存関係の挿入 (DI)コンテナーに登録する必要があります。 コンテナーは、コントローラーにサービスを提供します。
次の強調表示されているコードを使用して、Startup.cs
を更新します。
// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
上記のコードでは次の操作が行われます。
- 不要な
using
宣言を削除します。 - DI コンテナーにデータベース コンテキストを追加します。
- データベース コンテキストがメモリ内データベースを使用することを指定します。
コントローラーのスキャフォールディング
Controllers フォルダーを右クリックします。
[追加]>[スキャフォールディングされた新しい項目] を選択します。
[Entity Framework を使用したアクションがある API コントローラー] を選択してから、 [追加] を選択します。
[Entity Framework を使用したアクションがある API コントローラー] ダイアログで次を実行します。
- モデル クラスで [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 作成メソッドの確認
nameof 演算子を使用するために、PostTodoItem
で return ステートメントを置き換えます。
// POST: api/TodoItems
[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);
}
[HttpPost]
属性が示すように、上記のコードは HTTP POST メソッドです。 このメソッドは、HTTP 要求の本文から To Do アイテムの値を取得します。
詳細については、「Http[Verb] 属性を使用する属性ルーティング」を参照してください。
CreatedAtAction メソッド:
- 成功すると、HTTP 201 状態コードが返されます。 HTTP 201 は、サーバーに新しいリソースを作成する HTTP POST メソッドに対する標準の応答です。
- 応答に Location ヘッダーが追加されます。
Location
ヘッダーでは、新しく作成された To Do アイテムの URI が指定されます。 詳細については、「201 Created」を参照してください。 GetTodoItem
アクションを参照してLocation
ヘッダーの URI を作成します。 C# のnameof
キーワードを使って、CreatedAtAction
呼び出しでアクション名をハードコーディングすることを回避しています。
Postman のインストール
このチュートリアルでは、Postman を使用して Web API をテストします。
- Postman をインストールします。
- Web アプリを起動します。
- Postman を起動します。
- [SSL 証明書の確認] を無効にします。
- Windows 用 Postman: Windows 用 Postman [ファイル]>[設定] ([全般] タブ)、[SSL 証明書の確認] を無効にします。
- Windows 用 macOS: Windows 用 Postman [Postman]>[設定] ([全般] タブ)、[SSL 証明書の確認] を無効にします。
警告
コントローラーをテストした後、SSL 証明書の検証を再度有効にします。
Postman を使用した PostTodoItem のテスト
新しい要求を作成します。
HTTP メソッドを
POST
に設定します。URI を
https://localhost:<port>/api/todoitems
に設定します。 たとえば、「https://localhost:5001/api/todoitems
」のように入力します。[Body] タブを選択します。
[raw] ラジオ ボタンを選択します。
型を [JSON (application/json)] に設定します。
要求本文に、To Do アイテムの JSON を入力します。
{ "name":"walk dog", "isComplete":true }
[Send] を選択します。
Postman で Location ヘッダーの URI をテストする
[Response] ウィンドウで、 [Headers] タブを選択します。
[Location] ヘッダー値をコピーします。
HTTP メソッドを
GET
に設定します。URI を
https://localhost:<port>/api/todoitems/1
に設定します。 たとえば、「https://localhost:5001/api/todoitems/1
」のように入力します。[Send] を選択します。
GET メソッドの確認
これらのメソッドは、次の 2 つの GET エンドポイントを実装します。
GET /api/todoitems
GET /api/todoitems/{id}
ブラウザーまたは Postman から 2 つのエンドポイントを呼び出すことによって、アプリをテストします。 次に例を示します。
https://localhost:5001/api/todoitems
https://localhost:5001/api/todoitems/1
GetTodoItems
への呼び出しによって、次のような応答が生成されます。
[
{
"id": 1,
"name": "Item1",
"isComplete": false
}
]
Postman を使用して Get をテストする
- 新しい要求を作成します。
- HTTP メソッドを GET に設定します。
- 要求 URI を
https://localhost:<port>/api/todoitems
に設定します。 たとえば、https://localhost:5001/api/todoitems
のようにします。 - Postman で [Two pane view] を設定します。
- [Send] を選択します。
このアプリではメモリ内データベースが使用されます。 アプリが停止して開始された場合、上記の GET 要求はデータを返しません。 データが返されない場合は、アプリにデータを POST します。
ルーティングと URL パス
[HttpGet]
属性は、HTTP GET 要求に応答するメソッドを表します。 各メソッドの URL パスは次のように構成されます。
コントローラーの
Route
属性でテンプレート文字列を使用します。[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }
[controller]
をコントローラーの名前 (慣例では "Controller" サフィックスを除くコントローラー クラス名) に置き換えます。 このサンプルでは、コントローラー クラス名は TodoItemsController なので、コントローラー名は "TodoItems" です。 ASP.NET Core のルーティングでは、大文字と小文字が区別されません。[HttpGet]
属性にルート テンプレート (たとえば、[HttpGet("products")]
) がある場合は、それをパスに追加します。 このサンプルではテンプレートを使用しません。 詳細については、「Http[Verb] 属性を使用する属性ルーティング」を参照してください。
次の GetTodoItem
メソッドで、"{id}"
は To Do アイテムの一意識別子に使用するプレースホルダーの変数です。 GetTodoItem
が呼び出されると、その id
パラメーター内のメソッドに URL の "{id}"
の値が指定されます。
// GET: api/TodoItems/5
[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 で、ハンドルされない例外がないものと想定します。 ハンドルされない例外は 5xx エラーに変換されます。
ActionResult
戻り値の型は、幅広い範囲の HTTP 状態コードを表すことができます。 たとえば、GetTodoItem
は、次の 2 つの異なる状態値を返す可能性があります。
- 要求された ID と一致するアイテムがない場合、メソッドは 404 NotFound エラー コードを返します。
- それ以外の場合、メソッドは JSON 応答本文で 200 を返します。 戻り値が
item
の場合、HTTP 200 応答が返されます。
PutTodoItem メソッド
PutTodoItem
メソッドを検証します。
// PUT: api/TodoItems/5
[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 (No Content) となります。 HTTP 仕様に従って、PUT 要求では、変更だけでなく、更新されたエンティティ全体を送信するようクライアントに求めます。 部分的な更新をサポートするには、HTTP PATCH を使用します。
PutTodoItem
呼び出しでエラーが発生した場合、GET
を呼び出してデータベース内にアイテムがあることを確認してください。
PutTodoItem メソッドのテスト
このサンプルでは、アプリを起動するたびに開始することが必要なメモリ内データベースが使われています。 PUT 呼び出しを実行する前に、データベース内にアイテムが存在している必要があります。 GET を呼び出して、PUT 呼び出しを実行する前にデータベース内にアイテムが確実に存在していることを確認します。
Id = 1 の To Do アイテムを更新し、その名前を "feed fish" に設定します。
{
"id":1,
"name":"feed fish",
"isComplete":true
}
次の図は、Postman の更新を示しています。
DeleteTodoItem メソッド
DeleteTodoItem
メソッドを検証します。
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return todoItem;
}
DeleteTodoItem メソッドのテスト
Postman を使用して、To Do アイテムを削除します。
- メソッドを
DELETE
に設定します。 - 削除するオブジェクトの URI (たとえば、
https://localhost:5001/api/todoitems/1
) を設定します。 - [Send] を選択します。
過剰な投稿を防止する
現在、サンプル アプリでは TodoItem
オブジェクト全体が公開されています。 通常、運用環境のアプリでは、モデルのサブセットを使用して入力されるデータおよび返されるデータが制限されています。 その背景には複数の理由があり、セキュリティは主なものです。 モデルのサブセットは、通常、データ転送オブジェクト (DTO)、入力モデル、またはビュー モデルと呼ばれます。 この記事では DTO を使用しています。
DTO は次の目的で使用できます。
- 過剰な投稿を防止する。
- クライアントが表示しないことになっているプロパティを非表示にする。
- ペイロード サイズを減らすために、いくつかのプロパティを省略する。
- 入れ子になったオブジェクトを含むオブジェクト グラフをフラット化する。 フラット化されたオブジェクト グラフは、クライアントにとってより便利になる可能性があります。
DTO のアプローチを実演するために、TodoItem
クラスを更新して、シークレット フィールドを含めます。
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
public string Secret { get; set; }
}
シークレット フィールドは、このアプリでは非表示にする必要がありますが、管理アプリの場合は公開することを選択できます。
シークレット フィールドを投稿および取得できることを確認します。
次のように DTO モデルを作成します。
public class TodoItemDTO
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
TodoItemDTO
を使用するように TodoItemsController
を更新します。
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
[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);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
[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) =>
_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 に認証サポートを追加
ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。
Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
Azure に発行する
Azure へのデプロイについては、「クイックスタート: ASP.NET Web アプリをデプロイする」を参照してください。
その他の技術情報
このチュートリアルのサンプル コードを表示またはダウンロードします。 ダウンロード方法に関するページを参照してください。
詳細については、次のリソースを参照してください。
- ASP.NET Core を使って Web API を作成する
- チュートリアル: ASP.NET Core を使って最小 API を作成する
- Swagger/OpenAPI を使用する ASP.NET Core Web API のドキュメント
- RazorASP.NET Core での Entity Framework Core を使用した Pages - チュートリアル 1/8
- ASP.NET Core でのコントローラー アクションへのルーティング
- ASP.NET Core Web API のコントローラー アクションの戻り値の型
- Azure App Service に ASP.NET Core アプリを展開する
- ASP.NET Core のホストと展開
- ASP.NET Core で Web API を作成する