ASP.NET Core と MongoDB で Web API を作成する
Note
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、 .NET および .NET Core サポート ポリシーを参照してください。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。
現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
作成者: Pratik Khandelwal および Scott Addie
このチュートリアルでは、MongoDB NoSQL データベース上で Create、Read、Update、Delete の各操作 (CRUD) を実行する Web API を作成します。
このチュートリアルでは、次の作業を行う方法について説明します。
- MongoDB を構成する
- MongoDB データベースを作成する
- MongoDB のコレクションとスキーマを定義する
- Web API から MongoDB CRUD 操作を実行する
- JSON のシリアル化のカスタマイズ
前提条件
Visual Studio 2022 と ASP.NET と Web 開発ワークロード。
MongoDB を構成する
開発用コンピューター (Windows/Linux/macOS) 上のどこからでも MongoDB および Mongo DB Shell のアクセスを有効にします。
MongoDB Shell をダウンロードし、インストールします。
- macOS/Linux: MongoDB Shell の抽出先となるディレクトリを選択します。
mongosh
の作成されたパスをPATH
環境変数に追加します。 - Windows: MongoDB Shell (mongosh.exe) は C:\Users<user>\AppData\Local\Programs\mongosh にインストールされます。
mongosh.exe
の作成されたパスをPATH
環境変数に追加します。
- macOS/Linux: MongoDB Shell の抽出先となるディレクトリを選択します。
MongoDB をダウンロードし、インストールします。
- macOS/Linux: MongoDB がインストールされたディレクトリを確認します。通常は /usr/local/mongodb です。
mongodb
の作成されたパスをPATH
環境変数に追加します。 - Windows: 既定では、MongoDB は C:\Program Files\MongoDB にインストールされます。 C:\Program Files\MongoDB\Server\<version_number>\bin を
PATH
環境変数に追加します。
- macOS/Linux: MongoDB がインストールされたディレクトリを確認します。通常は /usr/local/mongodb です。
データ ストレージ ディレクトリの選択: データを格納するためのディレクトリを開発用コンピューター上で選択します。 存在しない場合はディレクトリを作成します。 MongoDB Shell では新しいディレクトリは作成されません。
- macOS/Linux:
/usr/local/var/mongodb
など。 - Windows:
C:\\BooksData
など。
- macOS/Linux:
OS のコマンド シェル (MongoDB Shell ではなく) で、次のコマンドを使って、既定のポート 27017 で MongoDB に接続します。
<data_directory_path>
を、前の手順で選択したディレクトリに置き換えます。mongod --dbpath <data_directory_path>
次の手順では、以前にインストールした MongoDB シェルを使用して、データベースを作成し、コレクションを作成し、ドキュメントを保存します。 MongoDB シェル コマンドの詳細については、「mongosh
」を参照してください。
mongosh.exe
を起動して、MongoDB コマンド シェル インスタンスを開きます。コマンド シェルで、次のコマンドを実行し、既定のテスト データベースに接続します。
mongosh
次のコマンドをコマンド シェルで実行します。
use BookStore
BookStore という名前のデータベースが、まだ存在しない場合は作成されます。 データベースが存在する場合は、トランザクションのために接続されます。
次のコマンドを使用して
Books
コレクションを作成します。db.createCollection('Books')
次のような結果が表示されます。
{ "ok" : 1 }
次のコマンドを使用して、
Books
コレクションのスキーマを定義し、2 つのドキュメントを挿入します。db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
次のような結果が表示されます。
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Note
前述の結果に示されている
ObjectId
は、実際のコマンド シェルの表示内容とは一致しません。次のコマンドを使用して、データベース内のドキュメントを表示します。
db.Books.find().pretty()
次のような結果が表示されます。
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
スキーマによって、自動生成された型が
ObjectId
の_id
プロパティが各ドキュメントに追加されます。
ASP.NET Core Web API プロジェクトを作成する
[ファイル]>[新規]>[プロジェクト] の順に移動します。
[ASP.NET Core Web API] プロジェクトの種類を選択し、[次へ] を選択します。
プロジェクトに「BookStoreApi」という名前を付け、[次へ] を選択します。
[.NET 8.0 (長期的なサポート)] フレームワークを選択し、[作成] を選択します。
[パッケージ マネージャー コンソール] ウィンドウで、プロジェクトのルートに移動します。 次のコマンドを実行して、MongoDB 用の .NET ドライバーをインストールします。
Install-Package MongoDB.Driver
モデルにエンティティを追加する
Models ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
Book
クラスをBook
ディレクトリに追加します。using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
上記のクラスでは、
Id
プロパティは:- 共通言語ランタイム (CLR) オブジェクトを MongoDB コレクションにマッピングするために必須です。
- このプロパティをドキュメントの主キーとするために、
[BsonId]
で注釈を付けられています。 [BsonRepresentation(BsonType.ObjectId)]
構造体ではなくstring
型としてパラメーターを渡すことができるようにするために、[BsonRepresentation(BsonType.ObjectId)]
で注釈を付けられています。 Mongo によってstring
からObjectId
への変換が処理されます。
BookName
プロパティには、[BsonElement]
属性を使用して注釈が付けられます。 属性の値Name
は、MongoDB コレクションでのプロパティ名を表します。
構成モデルを追加する
次のデータベース構成値を
appsettings.json
に追加します。{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
次のコードを使用して、
BookStoreDatabaseSettings
クラスをBookStoreDatabaseSettings
ディレクトリに追加します。namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
前述の
BookStoreDatabaseSettings
クラスは、appsettings.json
ファイルのBookStoreDatabase
プロパティ値を格納するために使用されます。 JSON と C# のプロパティ名には、マッピング処理を簡単にするために同じ名前が付けられています。次の強調表示されたコードを
Program.cs
に追加します。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
上のコードで、
appsettings.json
ファイルのBookStoreDatabase
セクションがバインドされている構成インスタンスは、Dependency Injection (DI) コンテナーに登録されています。 たとえば、BookStoreDatabaseSettings
オブジェクトのConnectionString
プロパティには、appsettings.json
のBookStoreDatabase:ConnectionString
プロパティが設定されています。次のコードを
Program.cs
の先頭に追加して、BookStoreDatabaseSettings
の参照を解決します。using BookStoreApi.Models;
CRUD 操作のサービスを追加する
Services ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
BooksService
クラスをBooksService
ディレクトリに追加します。using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
前述のコードでは、
BookStoreDatabaseSettings
インスタンスがコンストラクターの挿入によって DI から取得されます。 この手法で、「appsettings.json
」セクションで追加したappsettings.json
構成値にアクセスできます。次の強調表示されたコードを
Program.cs
に追加します。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
前述のコードでは、消費クラスへのコンストラクターの挿入をサポートする
BooksService
クラスが DI に登録されています。BooksService
がMongoClient
に直接依存しているため、シングルトン サービスの有効期間が最も適切です。 公式の Mongo Client 再利用ガイドラインに従い、シングルトン サービスの有効期間を使用して DI にMongoClient
を登録する必要があります。次のコードを
Program.cs
の先頭に追加して、BooksService
の参照を解決します。using BookStoreApi.Services;
BooksService
クラスは次の MongoDB.Driver
メンバーを使用して、データベースに対する CRUD 操作を実行します。
MongoClient: データベース操作を実行するためにサーバー インスタンスを読み取ります。 このクラスのコンストラクターは、MongoDB 接続文字列内で提供されます。
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: 操作を実行する Mongo データベースを表します。 このチュートリアルでは、インターフェイスで汎用の GetCollection<TDocument>(collection) メソッドを使って、特定のコレクション内のデータにアクセスします。 このメソッドが呼び出された後に、CRUD 操作をこのコレクションに対して実行します。
GetCollection<TDocument>(collection)
メソッドの呼び出しの内容は次のとおりです。collection
はコレクション名です。TDocument
はコレクションに格納されている CLR オブジェクト型です。
GetCollection<TDocument>(collection)
から、コレクションを表す GetCollection<TDocument>(collection)
オブジェクトが返されます。 このチュートリアルでは、コレクションに対して次のメソッドを呼び出します。
- DeleteOneAsync: 指定された検索基準と一致する 1 つのドキュメントを削除します。
- Find<TDocument>: 指定された検索基準と一致するコレクション内のすべてのドキュメントを返します。
- InsertOneAsync: 指定されたオブジェクトを新しいドキュメントとしてコレクションに挿入します。
- ReplaceOneAsync: 指定された検索基準と一致する 1 つのドキュメントを、指定されたオブジェクトで置き換えます。
コントローラーの追加
次のコードを使用して、BooksController
クラスを BooksController
ディレクトリに追加します。
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
上記の Web API コントローラー:
BooksService
クラスを使用して CRUD 操作を実行します。- GET、POST、PUT、DELETE HTTP 要求をサポートするアクション メソッドが含まれます。
Create
アクション メソッドで CreatedAtAction を呼び出して、CreatedAtAction 応答を返します。 状態コード 201 は、サーバーに新しいリソースを作成する HTTP POST メソッドに対する標準の応答です。CreatedAtAction
によって、応答にLocation
ヘッダーも追加されます。Location
ヘッダーでは、新しく作成されたブックの URI を指定します。
Web API をテストする
アプリケーションをビルドし、実行します。
https://localhost:<port>/api/books
に移動して、コントローラーのパラメーターなしのGet
アクション メソッドをテストします。ここで、<port>
は、自動的に割り当てられるアプリのポート番号です。[試してみる]、[取得] の順に選択します。 次のような JSON 応答が表示されます。[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
https://localhost:<port>/api/books/{id here}
に移動して、コントローラーのオーバーロードされたGet
アクション メソッドをテストします。 次のような JSON 応答が表示されます。{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
JSON シリアル化オプションを構成する
「Web API をテストする」セクションで返される JSON 応答について変更すべき 2 つの詳細があります。
- プロパティ名の既定の camel 形式は、CLR オブジェクトのプロパティ名の Pascal 形式と一致するように変更する必要があります
bookName
プロパティはName
として返される必要があります。
上記の要件を満たすには、次の変更を行います。
Program.cs
で、次の強調表示されたコードをAddControllers
メソッド呼び出しにチェーンします。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
上記の変更により、Web API のシリアル化された JSON 応答内のプロパティ名は、CLR のオブジェクトの種類での対応するプロパティ名と一致しています。 たとえば、
Book
クラスのAuthor
プロパティは、author
ではなくAuthor
としてシリアル化されます。Models/Book.cs
では、[JsonPropertyName]
属性を使用してBookName
プロパティに注釈を付けます。[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
属性の値Name
は、Web API のシリアル化された JSON 応答内のプロパティ名を表します。次のコードを
Models/Book.cs
の先頭に追加して、[JsonProperty]
属性の参照を解決します。using System.Text.Json.Serialization;
「Web API をテストする」セクションで定義されている手順を繰り返します。 JSON プロパティ名の違いに注意してください。
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 のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
その他のリソース
このチュートリアルでは、MongoDB NoSQL データベース上で Create、Read、Update、Delete の各操作 (CRUD) を実行する Web API を作成します。
このチュートリアルでは、次の作業を行う方法について説明します。
- MongoDB を構成する
- MongoDB データベースを作成する
- MongoDB のコレクションとスキーマを定義する
- Web API から MongoDB CRUD 操作を実行する
- JSON のシリアル化のカスタマイズ
前提条件
Visual Studio 2022 と ASP.NET と Web 開発ワークロード。
MongoDB を構成する
開発用コンピューター上のどこからでも MongoDB および Mongo DB Shell のアクセスを有効にします。
Windows の場合、既定では MongoDB が C:\Program Files\MongoDB にインストールされます。 C:\Program Files\MongoDB\Server\<version_number>\bin を
PATH
環境変数に追加します。MongoDB Shell をダウンロードし、それを抽出するディレクトリを選択します。
mongosh.exe
の作成されたパスをPATH
環境変数に追加します。データを格納するための開発用コンピューター上のディレクトリを選択します。 たとえば、Windows では C:\BooksData です。 存在しない場合はディレクトリを作成します。 mongo シェルでは新しいディレクトリは作成されません。
OS のコマンド シェル (MongoDB Shell ではなく) で、次のコマンドを使って、既定のポート 27017 で MongoDB に接続します。
<data_directory_path>
を、前の手順で選択したディレクトリに置き換えます。mongod --dbpath <data_directory_path>
次の手順では、以前にインストールした MongoDB シェルを使用して、データベースを作成し、コレクションを作成し、ドキュメントを保存します。 MongoDB シェル コマンドの詳細については、「mongosh
」を参照してください。
mongosh.exe
を起動して、MongoDB コマンド シェル インスタンスを開きます。コマンド シェルで、次のコマンドを実行して、既定のテスト データベースに接続します。
mongosh
次のコマンドをコマンド シェルで実行します。
use BookStore
BookStore という名前のデータベースが、まだ存在しない場合は作成されます。 データベースが存在する場合は、トランザクションのために接続されます。
次のコマンドを使用して
Books
コレクションを作成します。db.createCollection('Books')
次のような結果が表示されます。
{ "ok" : 1 }
次のコマンドを使用して、
Books
コレクションのスキーマを定義し、2 つのドキュメントを挿入します。db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
次のような結果が表示されます。
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Note
前述の結果に示されている
ObjectId
は、実際のコマンド シェルの表示内容とは一致しません。次のコマンドを使用して、データベース内のドキュメントを表示します。
db.Books.find().pretty()
次のような結果が表示されます。
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
スキーマによって、自動生成された型が
ObjectId
の_id
プロパティが各ドキュメントに追加されます。
ASP.NET Core Web API プロジェクトを作成する
[ファイル]>[新規]>[プロジェクト] の順に移動します。
[ASP.NET Core Web API] プロジェクトの種類を選択し、[次へ] を選択します。
プロジェクトに「BookStoreApi」という名前を付け、[次へ] を選択します。
[.NET 7.0 (Standard Term Support)] (.NET 7.0 (標準期間サポート)) フレームワークを選択し、[作成] を選択します。
[ツール] メニューで、[NuGet パッケージ マネージャー]>[パッケージ マネージャー コンソール] の順に選択します。
[パッケージ マネージャー コンソール] ウィンドウで、プロジェクトのルートに移動します。 次のコマンドを実行して、MongoDB 用の .NET ドライバーをインストールします。
Install-Package MongoDB.Driver
モデルにエンティティを追加する
Models ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
Book
クラスをBook
ディレクトリに追加します。using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
上記のクラスでは、
Id
プロパティは:- 共通言語ランタイム (CLR) オブジェクトを MongoDB コレクションにマッピングするために必須です。
- このプロパティをドキュメントの主キーとするために、
[BsonId]
で注釈を付けられています。 [BsonRepresentation(BsonType.ObjectId)]
構造体ではなくstring
型としてパラメーターを渡すことができるようにするために、[BsonRepresentation(BsonType.ObjectId)]
で注釈を付けられています。 Mongo によってstring
からObjectId
への変換が処理されます。
BookName
プロパティには、[BsonElement]
属性を使用して注釈が付けられます。 属性の値Name
は、MongoDB コレクションでのプロパティ名を表します。
構成モデルを追加する
次のデータベース構成値を
appsettings.json
に追加します。{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
次のコードを使用して、
BookStoreDatabaseSettings
クラスをBookStoreDatabaseSettings
ディレクトリに追加します。namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
前述の
BookStoreDatabaseSettings
クラスは、appsettings.json
ファイルのBookStoreDatabase
プロパティ値を格納するために使用されます。 JSON と C# のプロパティ名には、マッピング処理を簡単にするために同じ名前が付けられています。次の強調表示されたコードを
Program.cs
に追加します。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
上のコードで、
appsettings.json
ファイルのBookStoreDatabase
セクションがバインドされている構成インスタンスは、Dependency Injection (DI) コンテナーに登録されています。 たとえば、BookStoreDatabaseSettings
オブジェクトのConnectionString
プロパティには、appsettings.json
のBookStoreDatabase:ConnectionString
プロパティが設定されています。次のコードを
Program.cs
の先頭に追加して、BookStoreDatabaseSettings
の参照を解決します。using BookStoreApi.Models;
CRUD 操作のサービスを追加する
Services ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
BooksService
クラスをBooksService
ディレクトリに追加します。using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
前述のコードでは、
BookStoreDatabaseSettings
インスタンスがコンストラクターの挿入によって DI から取得されます。 この手法で、「appsettings.json
」セクションで追加したappsettings.json
構成値にアクセスできます。次の強調表示されたコードを
Program.cs
に追加します。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
前述のコードでは、消費クラスへのコンストラクターの挿入をサポートする
BooksService
クラスが DI に登録されています。BooksService
がMongoClient
に直接依存しているため、シングルトン サービスの有効期間が最も適切です。 公式の Mongo Client 再利用ガイドラインに従い、シングルトン サービスの有効期間を使用して DI にMongoClient
を登録する必要があります。次のコードを
Program.cs
の先頭に追加して、BooksService
の参照を解決します。using BookStoreApi.Services;
BooksService
クラスは次の MongoDB.Driver
メンバーを使用して、データベースに対する CRUD 操作を実行します。
MongoClient: データベース操作を実行するためにサーバー インスタンスを読み取ります。 このクラスのコンストラクターには MongoDB 接続文字列が提供されます。
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: 操作を実行する Mongo データベースを表します。 このチュートリアルでは、インターフェイスで汎用の GetCollection<TDocument>(collection) メソッドを使って、特定のコレクション内のデータにアクセスします。 このメソッドが呼び出された後に、CRUD 操作をこのコレクションに対して実行します。
GetCollection<TDocument>(collection)
メソッドの呼び出しの内容は次のとおりです。collection
はコレクション名です。TDocument
はコレクションに格納されている CLR オブジェクト型です。
GetCollection<TDocument>(collection)
から、コレクションを表す GetCollection<TDocument>(collection)
オブジェクトが返されます。 このチュートリアルでは、コレクションに対して次のメソッドを呼び出します。
- DeleteOneAsync: 指定された検索基準と一致する 1 つのドキュメントを削除します。
- Find<TDocument>: 指定された検索基準と一致するコレクション内のすべてのドキュメントを返します。
- InsertOneAsync: 指定されたオブジェクトを新しいドキュメントとしてコレクションに挿入します。
- ReplaceOneAsync: 指定された検索基準と一致する 1 つのドキュメントを、指定されたオブジェクトで置き換えます。
コントローラーの追加
次のコードを使用して、BooksController
クラスを BooksController
ディレクトリに追加します。
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
上記の Web API コントローラー:
BooksService
クラスを使用して CRUD 操作を実行します。- GET、POST、PUT、DELETE HTTP 要求をサポートするアクション メソッドが含まれます。
Create
アクション メソッドで CreatedAtAction を呼び出して、CreatedAtAction 応答を返します。 状態コード 201 は、サーバーに新しいリソースを作成する HTTP POST メソッドに対する標準の応答です。CreatedAtAction
によって、応答にLocation
ヘッダーも追加されます。Location
ヘッダーでは、新しく作成されたブックの URI を指定します。
Web API をテストする
アプリケーションをビルドし、実行します。
https://localhost:<port>/api/books
に移動して、コントローラーのパラメーターなしの<port>
アクション メソッドをテストします。ここで、Get
は、自動的に割り当てられるアプリのポート番号です。 次のような JSON 応答が表示されます。[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
https://localhost:<port>/api/books/{id here}
に移動して、コントローラーのオーバーロードされたGet
アクション メソッドをテストします。 次のような JSON 応答が表示されます。{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
JSON シリアル化オプションを構成する
「Web API をテストする」セクションで返される JSON 応答について変更すべき 2 つの詳細があります。
- プロパティ名の既定の camel 形式は、CLR オブジェクトのプロパティ名の Pascal 形式と一致するように変更する必要があります
bookName
プロパティはName
として返される必要があります。
上記の要件を満たすには、次の変更を行います。
Program.cs
で、次の強調表示されたコードをAddControllers
メソッド呼び出しにチェーンします。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
上記の変更により、Web API のシリアル化された JSON 応答内のプロパティ名は、CLR のオブジェクトの種類での対応するプロパティ名と一致しています。 たとえば、
Book
クラスのAuthor
プロパティは、author
ではなくAuthor
としてシリアル化されます。Models/Book.cs
では、[JsonPropertyName]
属性を使用してBookName
プロパティに注釈を付けます。[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
属性の値Name
は、Web API のシリアル化された JSON 応答内のプロパティ名を表します。次のコードを
Models/Book.cs
の先頭に追加して、[JsonProperty]
属性の参照を解決します。using System.Text.Json.Serialization;
「Web API をテストする」セクションで定義されている手順を繰り返します。 JSON プロパティ名の違いに注意してください。
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 のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
その他のリソース
このチュートリアルでは、MongoDB NoSQL データベース上で Create、Read、Update、Delete の各操作 (CRUD) を実行する Web API を作成します。
このチュートリアルでは、次の作業を行う方法について説明します。
- MongoDB を構成する
- MongoDB データベースを作成する
- MongoDB のコレクションとスキーマを定義する
- Web API から MongoDB CRUD 操作を実行する
- JSON のシリアル化のカスタマイズ
前提条件
- Visual Studio 2022 と ASP.NET と Web 開発ワークロード。
- .NET 6.0 SDK
MongoDB を構成する
開発用コンピューター上のどこからでも MongoDB および Mongo DB Shell のアクセスを有効にします。
Windows の場合、既定では MongoDB が C:\Program Files\MongoDB にインストールされます。 C:\Program Files\MongoDB\Server\<version_number>\bin を
PATH
環境変数に追加します。MongoDB Shell をダウンロードし、それを抽出するディレクトリを選択します。
mongosh.exe
の作成されたパスをPATH
環境変数に追加します。データを格納するための開発用コンピューター上のディレクトリを選択します。 たとえば、Windows では C:\BooksData です。 存在しない場合はディレクトリを作成します。 mongo シェルでは新しいディレクトリは作成されません。
OS のコマンド シェル (MongoDB Shell ではなく) で、次のコマンドを使って、既定のポート 27017 で MongoDB に接続します。
<data_directory_path>
を、前の手順で選択したディレクトリに置き換えます。mongod --dbpath <data_directory_path>
次の手順では、以前にインストールした MongoDB シェルを使用して、データベースを作成し、コレクションを作成し、ドキュメントを保存します。 MongoDB シェル コマンドの詳細については、「mongosh
」を参照してください。
mongosh.exe
を起動して、MongoDB コマンド シェル インスタンスを開きます。コマンド シェルで、次のコマンドを実行して、既定のテスト データベースに接続します。
mongosh
次のコマンドをコマンド シェルで実行します。
use BookStore
BookStore という名前のデータベースが、まだ存在しない場合は作成されます。 データベースが存在する場合は、トランザクションのために接続されます。
次のコマンドを使用して
Books
コレクションを作成します。db.createCollection('Books')
次のような結果が表示されます。
{ "ok" : 1 }
次のコマンドを使用して、
Books
コレクションのスキーマを定義し、2 つのドキュメントを挿入します。db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
次のような結果が表示されます。
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Note
前述の結果に示されている
ObjectId
は、実際のコマンド シェルの表示内容とは一致しません。次のコマンドを使用して、データベース内のドキュメントを表示します。
db.Books.find().pretty()
次のような結果が表示されます。
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
スキーマによって、自動生成された型が
ObjectId
の_id
プロパティが各ドキュメントに追加されます。
ASP.NET Core Web API プロジェクトを作成する
[ファイル]>[新規]>[プロジェクト] の順に移動します。
[ASP.NET Core Web API] プロジェクトの種類を選択し、[次へ] を選択します。
プロジェクトに「BookStoreApi」という名前を付け、[次へ] を選択します。
[.NET 6.0 (長期的なサポート)] フレームワークを選択し、[作成] を選択します。
[パッケージ マネージャー コンソール] ウィンドウで、プロジェクトのルートに移動します。 次のコマンドを実行して、MongoDB 用の .NET ドライバーをインストールします。
Install-Package MongoDB.Driver
モデルにエンティティを追加する
Models ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
Book
クラスをBook
ディレクトリに追加します。using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
上記のクラスでは、
Id
プロパティは:- 共通言語ランタイム (CLR) オブジェクトを MongoDB コレクションにマッピングするために必須です。
- このプロパティをドキュメントの主キーとするために、
[BsonId]
で注釈を付けられています。 [BsonRepresentation(BsonType.ObjectId)]
構造体ではなくstring
型としてパラメーターを渡すことができるようにするために、[BsonRepresentation(BsonType.ObjectId)]
で注釈を付けられています。 Mongo によってstring
からObjectId
への変換が処理されます。
BookName
プロパティには、[BsonElement]
属性を使用して注釈が付けられます。 属性の値Name
は、MongoDB コレクションでのプロパティ名を表します。
構成モデルを追加する
次のデータベース構成値を
appsettings.json
に追加します。{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
次のコードを使用して、
BookStoreDatabaseSettings
クラスをBookStoreDatabaseSettings
ディレクトリに追加します。namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
前述の
BookStoreDatabaseSettings
クラスは、appsettings.json
ファイルのBookStoreDatabase
プロパティ値を格納するために使用されます。 JSON と C# のプロパティ名には、マッピング処理を簡単にするために同じ名前が付けられています。次の強調表示されたコードを
Program.cs
に追加します。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
上のコードで、
appsettings.json
ファイルのBookStoreDatabase
セクションがバインドされている構成インスタンスは、Dependency Injection (DI) コンテナーに登録されています。 たとえば、BookStoreDatabaseSettings
オブジェクトのConnectionString
プロパティには、appsettings.json
のBookStoreDatabase:ConnectionString
プロパティが設定されています。次のコードを
Program.cs
の先頭に追加して、BookStoreDatabaseSettings
の参照を解決します。using BookStoreApi.Models;
CRUD 操作のサービスを追加する
Services ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
BooksService
クラスをBooksService
ディレクトリに追加します。using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
前述のコードでは、
BookStoreDatabaseSettings
インスタンスがコンストラクターの挿入によって DI から取得されます。 この手法で、「appsettings.json
」セクションで追加したappsettings.json
構成値にアクセスできます。次の強調表示されたコードを
Program.cs
に追加します。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
前述のコードでは、消費クラスへのコンストラクターの挿入をサポートする
BooksService
クラスが DI に登録されています。BooksService
がMongoClient
に直接依存しているため、シングルトン サービスの有効期間が最も適切です。 公式の Mongo Client 再利用ガイドラインに従い、シングルトン サービスの有効期間を使用して DI にMongoClient
を登録する必要があります。次のコードを
Program.cs
の先頭に追加して、BooksService
の参照を解決します。using BookStoreApi.Services;
BooksService
クラスは次の MongoDB.Driver
メンバーを使用して、データベースに対する CRUD 操作を実行します。
MongoClient: データベース操作を実行するためにサーバー インスタンスを読み取ります。 このクラスのコンストラクターには MongoDB 接続文字列が提供されます。
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: 操作を実行する Mongo データベースを表します。 このチュートリアルでは、インターフェイスで汎用の GetCollection<TDocument>(collection) メソッドを使って、特定のコレクション内のデータにアクセスします。 このメソッドが呼び出された後に、CRUD 操作をこのコレクションに対して実行します。
GetCollection<TDocument>(collection)
メソッドの呼び出しの内容は次のとおりです。collection
はコレクション名です。TDocument
はコレクションに格納されている CLR オブジェクト型です。
GetCollection<TDocument>(collection)
から、コレクションを表す GetCollection<TDocument>(collection)
オブジェクトが返されます。 このチュートリアルでは、コレクションに対して次のメソッドを呼び出します。
- DeleteOneAsync: 指定された検索基準と一致する 1 つのドキュメントを削除します。
- Find<TDocument>: 指定された検索基準と一致するコレクション内のすべてのドキュメントを返します。
- InsertOneAsync: 指定されたオブジェクトを新しいドキュメントとしてコレクションに挿入します。
- ReplaceOneAsync: 指定された検索基準と一致する 1 つのドキュメントを、指定されたオブジェクトで置き換えます。
コントローラーの追加
次のコードを使用して、BooksController
クラスを BooksController
ディレクトリに追加します。
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
上記の Web API コントローラー:
BooksService
クラスを使用して CRUD 操作を実行します。- GET、POST、PUT、DELETE HTTP 要求をサポートするアクション メソッドが含まれます。
Create
アクション メソッドで CreatedAtAction を呼び出して、CreatedAtAction 応答を返します。 状態コード 201 は、サーバーに新しいリソースを作成する HTTP POST メソッドに対する標準の応答です。CreatedAtAction
によって、応答にLocation
ヘッダーも追加されます。Location
ヘッダーでは、新しく作成されたブックの URI を指定します。
Web API をテストする
アプリケーションをビルドし、実行します。
https://localhost:<port>/api/books
に移動して、コントローラーのパラメーターなしの<port>
アクション メソッドをテストします。ここで、Get
は、自動的に割り当てられるアプリのポート番号です。 次のような JSON 応答が表示されます。[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
https://localhost:<port>/api/books/{id here}
に移動して、コントローラーのオーバーロードされたGet
アクション メソッドをテストします。 次のような JSON 応答が表示されます。{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
JSON シリアル化オプションを構成する
「Web API をテストする」セクションで返される JSON 応答について変更すべき 2 つの詳細があります。
- プロパティ名の既定の camel 形式は、CLR オブジェクトのプロパティ名の Pascal 形式と一致するように変更する必要があります
bookName
プロパティはName
として返される必要があります。
上記の要件を満たすには、次の変更を行います。
Program.cs
で、次の強調表示されたコードをAddControllers
メソッド呼び出しにチェーンします。var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
上記の変更により、Web API のシリアル化された JSON 応答内のプロパティ名は、CLR のオブジェクトの種類での対応するプロパティ名と一致しています。 たとえば、
Book
クラスのAuthor
プロパティは、author
ではなくAuthor
としてシリアル化されます。Models/Book.cs
では、[JsonPropertyName]
属性を使用してBookName
プロパティに注釈を付けます。[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
[JsonPropertyName]
属性の値Name
は、Web API のシリアル化された JSON 応答内のプロパティ名を表します。次のコードを
Models/Book.cs
の先頭に追加して、[JsonProperty]
属性の参照を解決します。using System.Text.Json.Serialization;
「Web API をテストする」セクションで定義されている手順を繰り返します。 JSON プロパティ名の違いに注意してください。
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 のアクセス制御
- Federation Gateway
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。
その他のリソース
このチュートリアルでは、MongoDB NoSQL データベース上で Create、Read、Update、Delete の各操作 (CRUD) を実行する Web API を作成します。
このチュートリアルでは、次の作業を行う方法について説明します。
- MongoDB を構成する
- MongoDB データベースを作成する
- MongoDB のコレクションとスキーマを定義する
- Web API から MongoDB CRUD 操作を実行する
- JSON のシリアル化のカスタマイズ
サンプル コードを表示またはダウンロードします (ダウンロード方法)。
必須コンポーネント
- .NET Core SDK 3.0 以降
- Visual Studio 2019 と ASP.NET と Web 開発ワークロード
- MongoDB
MongoDB を構成する
Windows を使用する場合、既定では MongoDB は C:\Program Files\MongoDB にインストールされます。 C:\Program Files\MongoDB\Server\<version_number>\bin を Path
環境変数に追加します。 この変更により、開発用コンピューターのどこからでも MongoDB にアクセスできるようになります。
次の手順では mongo シェルを使用して、データベースを作成し、コレクションを作成し、ドキュメントを保存します。 mongo のシェル コマンドについて詳しくは、「Working with the mongo Shell」(mongo シェルの使用) をご覧ください。
データを格納するために開発用コンピューター上のディレクトリを選択します。 たとえば、Windows では C:\BooksData です。 存在しない場合はディレクトリを作成します。 mongo シェルでは新しいディレクトリは作成されません。
コマンド シェルを開きます。 次のコマンドを実行して、既定のポート 27017 で MongoDB に接続します。 忘れずに、前の手順で選択したディレクトリで
<data_directory_path>
を置き換えます。mongod --dbpath <data_directory_path>
別のコマンド シェル インスタンスを開きます。 次のコマンドを実行して、既定のテスト データベースに接続します。
mongo
コマンド シェルで次のコマンドを実行します。
use BookstoreDb
BookstoreDb という名前のデータベースが、まだ存在していない場合は作成されます。 データベースが存在する場合は、トランザクションのために接続されます。
次のコマンドを使用して
Books
コレクションを作成します。db.createCollection('Books')
次のような結果が表示されます。
{ "ok" : 1 }
次のコマンドを使用して、
Books
コレクションのスキーマを定義し、2 つのドキュメントを挿入します。db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
次のような結果が表示されます。
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5bfd996f7b8e48dc15ff215d"), ObjectId("5bfd996f7b8e48dc15ff215e") ] }
Note
この記事に示されている ID は、このサンプルを実行するときの ID とは一致していません。
次のコマンドを使用して、データベース内のドキュメントを表示します。
db.Books.find({}).pretty()
次のような結果が表示されます。
{ "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
スキーマによって、自動生成された型が
ObjectId
の_id
プロパティが各ドキュメントに追加されます。
データベースの準備ができました。 ASP.NET Core Web API の作成を開始できます。
ASP.NET Core Web API プロジェクトを作成する
[ファイル]>[新規]>[プロジェクト] の順に移動します。
[ASP.NET Core Web アプリケーション] プロジェクトの種類を選択し、 [次へ] を選択します。
プロジェクトに BooksApi という名前を付けて、 [作成] を選択します。
[.NET Core] ターゲット フレームワークと [ASP.NET Core 3.0] を選択します。 [API] プロジェクト テンプレートを選択し、 [作成] を選択します。
NuGet ギャラリー:MongoDB.Driver に関するページを参照して、MongoDB 用 .NET ドライバーの最新の安定バージョンを確認します。 [パッケージ マネージャー コンソール] ウィンドウで、プロジェクトのルートに移動します。 次のコマンドを実行して、MongoDB 用の .NET ドライバーをインストールします。
Install-Package MongoDB.Driver -Version {VERSION}
モデルにエンティティを追加する
Models ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
Book
クラスをBook
ディレクトリに追加します。using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BooksApi.Models { public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } public decimal Price { get; set; } public string Category { get; set; } public string Author { get; set; } } }
上記のクラスでは、
Id
プロパティは:- 共通言語ランタイム (CLR) オブジェクトを MongoDB コレクションにマッピングするために必須です。
- このプロパティをドキュメントの主キーとするために、
[BsonId]
で注釈を付けられています。 [BsonRepresentation(BsonType.ObjectId)]
構造体ではなくstring
型としてパラメーターを渡すことができるようにするために、[BsonRepresentation(BsonType.ObjectId)]
で注釈を付けられています。 Mongo によってstring
からObjectId
への変換が処理されます。
BookName
プロパティには、[BsonElement]
属性を使用して注釈が付けられます。 属性の値Name
は、MongoDB コレクションでのプロパティ名を表します。
構成モデルを追加する
次のデータベース構成値を
appsettings.json
に追加します。{ "BookstoreDatabaseSettings": { "BooksCollectionName": "Books", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookstoreDb" }, "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } } }
次のコードを使用して、
BookstoreDatabaseSettings.cs
ファイルを Models ディレクトリに追加します。namespace BooksApi.Models { public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings { public string BooksCollectionName { get; set; } public string ConnectionString { get; set; } public string DatabaseName { get; set; } } public interface IBookstoreDatabaseSettings { string BooksCollectionName { get; set; } string ConnectionString { get; set; } string DatabaseName { get; set; } } }
前述の
BookstoreDatabaseSettings
クラスは、appsettings.json
ファイルのBookstoreDatabaseSettings
プロパティ値を格納するために使用されます。 JSON と C# のプロパティ名には、マッピング処理を簡単にするために同じ名前が付けられています。次の強調表示されたコードを
Startup.ConfigureServices
に追加します。public void ConfigureServices(IServiceCollection services) { // requires using Microsoft.Extensions.Options services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddControllers(); }
上のコードでは以下の操作が行われます。
appsettings.json
ファイルのBookstoreDatabaseSettings
セクションがバインドされている構成インスタンスは、Dependency Injection (DI) コンテナーに登録されています。 たとえば、BookstoreDatabaseSettings
オブジェクトのConnectionString
プロパティには、appsettings.json
のBookstoreDatabaseSettings:ConnectionString
プロパティが設定されています。IBookstoreDatabaseSettings
インターフェイスは、シングルトンIBookstoreDatabaseSettings
で DI に登録されています。 挿入されると、インターフェイス インスタンスはBookstoreDatabaseSettings
オブジェクトに解決されます。
次のコードを
Startup.cs
の先頭に追加して、BookstoreDatabaseSettings
とIBookstoreDatabaseSettings
の参照を解決します。using BooksApi.Models;
CRUD 操作のサービスを追加する
Services ディレクトリをプロジェクトのルートに追加します。
次のコードを使用して、
BookService
クラスをBookService
ディレクトリに追加します。using BooksApi.Models; using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace BooksApi.Services { public class BookService { private readonly IMongoCollection<Book> _books; public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); } public List<Book> Get() => _books.Find(book => true).ToList(); public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault(); public Book Create(Book book) { _books.InsertOne(book); return book; } public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn); public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id); public void Remove(string id) => _books.DeleteOne(book => book.Id == id); } }
前述のコードでは、
IBookstoreDatabaseSettings
インスタンスがコンストラクターの挿入によって DI から取得されます。 この手法で、「appsettings.json
」セクションで追加したappsettings.json
構成値にアクセスできます。次の強調表示されたコードを
Startup.ConfigureServices
に追加します。public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers(); }
前述のコードでは、消費クラスへのコンストラクターの挿入をサポートする
BookService
クラスが DI に登録されています。BookService
がMongoClient
に直接依存しているため、シングルトン サービスの有効期間が最も適切です。 公式の Mongo Client 再利用ガイドラインに従い、シングルトン サービスの有効期間を使用して DI にMongoClient
を登録する必要があります。次のコードを
Startup.cs
の先頭に追加して、BookService
の参照を解決します。using BooksApi.Services;
BookService
クラスは次の MongoDB.Driver
メンバーを使用して、データベースに対する CRUD 操作を実行します。
MongoClient: データベース操作を実行するためにサーバー インスタンスを読み取ります。 このクラスのコンストラクターには MongoDB 接続文字列が提供されます。
public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); }
IMongoDatabase: 操作を実行する Mongo データベースを表します。 このチュートリアルでは、インターフェイスで汎用の GetCollection<TDocument>(collection) メソッドを使って、特定のコレクション内のデータにアクセスします。 このメソッドが呼び出された後に、CRUD 操作をこのコレクションに対して実行します。
GetCollection<TDocument>(collection)
メソッドの呼び出しの内容は次のとおりです。collection
はコレクション名です。TDocument
はコレクションに格納されている CLR オブジェクト型です。
GetCollection<TDocument>(collection)
から、コレクションを表す GetCollection<TDocument>(collection)
オブジェクトが返されます。 このチュートリアルでは、コレクションに対して次のメソッドを呼び出します。
- DeleteOne:指定された検索基準と一致する 1 つのドキュメントを削除します。
- Find<TDocument>: 指定された検索基準と一致するコレクション内のすべてのドキュメントを返します。
- InsertOne:指定されたオブジェクトを新しいドキュメントとしてコレクションに挿入します。
- ReplaceOne:指定された検索基準と一致する 1 つのドキュメントを、指定されたオブジェクトで置き換えます。
コントローラーの追加
次のコードを使用して、BooksController
クラスを BooksController
ディレクトリに追加します。
using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace BooksApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private readonly BookService _bookService;
public BooksController(BookService bookService)
{
_bookService = bookService;
}
[HttpGet]
public ActionResult<List<Book>> Get() =>
_bookService.Get();
[HttpGet("{id:length(24)}", Name = "GetBook")]
public ActionResult<Book> Get(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
return book;
}
[HttpPost]
public ActionResult<Book> Create(Book book)
{
_bookService.Create(book);
return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
}
[HttpPut("{id:length(24)}")]
public IActionResult Update(string id, Book bookIn)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Update(id, bookIn);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public IActionResult Delete(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Remove(id);
return NoContent();
}
}
}
上記の Web API コントローラー:
BookService
クラスを使用して CRUD 操作を実行します。- GET、POST、PUT、DELETE HTTP 要求をサポートするアクション メソッドが含まれます。
Create
アクション メソッドで CreatedAtRoute を呼び出して、CreatedAtRoute 応答を返します。 状態コード 201 は、サーバーに新しいリソースを作成する HTTP POST メソッドに対する標準の応答です。CreatedAtRoute
によって、応答にLocation
ヘッダーも追加されます。Location
ヘッダーでは、新しく作成されたブックの URI を指定します。
Web API をテストする
アプリケーションをビルドし、実行します。
https://localhost:<port>/api/books
に移動して、コントローラーのパラメーターなしのGet
アクション メソッドをテストします。 次の JSON 応答が示されます。[ { "id":"5bfd996f7b8e48dc15ff215d", "bookName":"Design Patterns", "price":54.93, "category":"Computers", "author":"Ralph Johnson" }, { "id":"5bfd996f7b8e48dc15ff215e", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" } ]
https://localhost:<port>/api/books/{id here}
に移動して、コントローラーのオーバーロードされたGet
アクション メソッドをテストします。 次の JSON 応答が示されます。{ "id":"{ID}", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" }
JSON シリアル化オプションを構成する
「Web API をテストする」セクションで返される JSON 応答について変更すべき 2 つの詳細があります。
- プロパティ名の既定の camel 形式は、CLR オブジェクトのプロパティ名の Pascal 形式と一致するように変更する必要があります
bookName
プロパティはName
として返される必要があります。
上記の要件を満たすには、次の変更を行います。
Json.NET は ASP.NET 共有フレームワークから削除されています。
Microsoft.AspNetCore.Mvc.NewtonsoftJson
へのパッケージ参照を追加します。Startup.ConfigureServices
で、次の強調表示されたコードをAddControllers
メソッド呼び出しにチェーンします。public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers() .AddNewtonsoftJson(options => options.UseMemberCasing()); }
上記の変更により、Web API のシリアル化された JSON 応答内のプロパティ名は、CLR のオブジェクトの種類での対応するプロパティ名と一致しています。 たとえば、
Book
クラスのAuthor
プロパティはAuthor
としてシリアル化されます。Models/Book.cs
Models/Book.cs
では、Models/Book.cs
プロパティに次の[JsonProperty]
属性を使用して注釈を付けます。[BsonElement("Name")] [JsonProperty("Name")] public string BookName { get; set; }
[JsonProperty]
属性の値Name
は、Web API のシリアル化された JSON 応答内のプロパティ名を表します。次のコードを
Models/Book.cs
の先頭に追加して、[JsonProperty]
属性の参照を解決します。using Newtonsoft.Json;
「Web API をテストする」セクションで定義されている手順を繰り返します。 JSON プロパティ名の違いに注意してください。
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 IdentityServer。 Duende IdentityServer はサードパーティ製品です。
Duende IdentityServer は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende IdentityServer により、次のセキュリティ機能が有効になります。
- サービスとしての認証 (AaaS)
- 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
- API のアクセス制御
- Federation Gateway
詳細については、「Duende IdentityServer の概要」をご覧ください。
その他の認証プロバイダーについて詳しくは、「ASP.NET Core のコミュニティ OSS 認証オプション」を参照してください
次の手順
ASP.NET Core Web API の構築について詳しくは、次のリソースを参照してください。
ASP.NET Core