演習 - データベース サービスを使用して .NET Aspire プロジェクトのデータを保持する
この演習では、会社で開発中のクラウドネイティブ アプリの現在のデータ ストアを置き換えます。 現在、このアプリは、ローカルに保存されている SQLite データベースをカタログ データに使用し、顧客の買い物かごにはメモリ内 Redis キャッシュを使用しています。 既存のデータ ストアを PostgreSQL と MongoDB に置き換えます。
必須コンポーネントのインストール
.NET Aspire の前提条件は次のとおりです。
- .NET 8
- Visual Studio 2022 Preview
- Docker Desktop または Podman
- Visual Studio の .NET Aspire ワークロード
前提条件を既にインストールしている場合は、既存のアプリの複製に進むことができます。
.NET 8 をインストールする
この .NET 8 のリンクに従って、オペレーティング システムに適したインストーラーを選択します。 たとえば、Windows 11 と最新のプロセッサを使用している場合は、x64 .NET 8 SDK for Windows を選択します。
ダウンロードが完了した後、インストーラーを実行し、指示に従います。 ターミナル ウィンドウで、次のコマンドを実行して、インストールが成功したことを確認します。
dotnet --version
インストールした .NET SDK のバージョン番号が表示されるはずです。 次に例を示します。
8.0.300-preview.24203.14
Visual Studio 2022 Preview をインストールする
この Visual Studio 2022 Preview のリンクに従って、[プレビューのダウンロード] を選択します。 ダウンロードが完了した後、インストーラーを実行し、指示に従います。
Docker Desktop のインストール
この Docker Desktop のリンクに従って、オペレーティング システムに適したインストーラーを選択します。 ダウンロードが完了した後、インストーラーを実行し、指示に従います。
Docker Desktop アプリケーションを開き、サービス契約に同意します。
Visual Studio に .NET Aspire ワークロードをインストールする
.NET CLI を使用して、.NET Aspire ワークロードをインストールします。
ターミナルを開きます。
次のコマンドを使用して、.NET Aspire ワークロードをインストールします。
dotnet workload update dotnet workload install aspire dotnet workload list
.NET Aspire ワークロードの詳細が表示されます。
Installed Workload Id Manifest Version Installation Source --------------------------------------------------------------------------------------------- aspire 8.0.0/8.0.100 SDK 8.0.300-preview.24203, VS 17.10.34902.84 Use `dotnet workload search` to find additional workloads to install.
Northern Mountains アプリを複製して変更する
git
を使用して、現在の Northern Mountains アプリを取得しましょう。
コマンド ラインで、コードを操作できる任意のフォルダーを参照します。
次のコマンドを実行して、Northern Mountains eShop サンプル アプリケーションを複製します。
git clone -b aspire-databases https://github.com/MicrosoftDocs/mslearn-aspire-starter
Visual Studio を起動し、[プロジェクトやソリューションを開く] を選択します。
eShop を複製したフォルダーに移動し、[スタート] フォルダーを開いて、[eShop.databases.sln] ファイルを選択し、[開く] を選択します。
ソリューション エクスプローラーで [eShop.AppHost] プロジェクトを開き、[Program.cs] ファイルを開きます。
// Databases var basketStore = builder.AddRedis("BasketStore").WithRedisCommander(); // Identity Providers var idp = builder.AddKeycloakContainer("idp", tag: "23.0") .ImportRealms("../Keycloak/data/import"); // DB Manager Apps builder.AddProject<Projects.Catalog_Data_Manager>("catalog-db-mgr"); // API Apps var catalogApi = builder.AddProject<Projects.Catalog_API>("catalog-api"); var basketApi = builder.AddProject<Projects.Basket_API>("basket-api") .WithReference(basketStore) .WithReference(idp); // Apps // Force HTTPS profile for web app (required for OIDC operations) var webApp = builder.AddProject<Projects.WebApp>("webapp") .WithReference(catalogApi) .WithReference(basketApi) .WithReference(idp, env: "Identity__ClientSecret");
上記のコードは、アプリの現在の構成を示しています。 このアプリでは、買い物かご用のストアとして Redis Cache を使用します。
アプリの残りの部分を調べ、Catalog.Data.Manager プロジェクトと Catalog.API プロジェクトに焦点を当てて、ローカルに保存された SQLite データベースがどのように使用されるかを確認します。
アプリを起動するには、F5 キーを押すか、[デバッグ] > [デバッグの開始] の順に選択します。
[Docker Desktop の起動] ダイアログが表示されたら、[はい] を選択します。
eShop .NET Aspire ダッシュボードが表示されたら、webappリソースに対して、セキュリティで保護されたエンドポイントを選択します。
アプリがブラウザーで開きます。 アプリを調べて、そのしくみを確認できます。
テスト ユーザーの資格情報は、test@example.com と P@$$w0rd1 です。
デバッグを停止するには、Shift+F5 キーを押すか、[デバッグ] > [デバッグの停止] の順に選択します。
.NET Aspire PostgreSQL コンポーネントを追加する
カタログ マイクロサービスを担当するチームは、ローカルに保存された SQLite データベースを使用するようにアプリを構築しました。 このアプローチは開発には適していますが、チームは、運用環境にはより堅牢なデータベースを使用したいと考えています。
2 つのプロジェクト (Catalog.Data.Manager プロジェクトと Catalog.API プロジェクト) は SQLite データベースに接続されています。 データ マネージャーは、データベースにデータをシードするためにのみ使用されるため、Catalog.API プロジェクトに焦点を当てる必要があります。
ソリューション エクスプローラーで [Catalog.API] プロジェクトを右クリックし、[追加]>[.NET Aspire パッケージ] の順に選択します。
検索ボックスで、末尾に Npgsql.EntityFramework を追加し、Enter キーを押します。
左側の結果で、[Aspire.Npgsql.EntityFrameworkCore.PostgreSQL] を選択します。
右側でバージョン ドロップダウンを選択し、最新の [8.0.0] リリースを選択します。
[インストール] を選択します。
[変更のプレビュー] ダイアログが表示された場合は、[適用] を選びます。
[ライセンスの同意] ウィンドウで、[同意する] を選択します。
ソリューション エクスプローラーで、[Catalog.API] プロジェクトを選択して、[Catalog.API.csproj] ファイルの内容を表示します。
Microsoft.EntityFrameworkCore.Sqlite の
PackageReference
を削除します。<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
新しい PostgreSQL DbContext を登録する
ソリューション エクスプローラーで、[Catalog.API] プロジェクトを展開し、[Program.cs] ファイルを開きます。
SQLite DbContext を次のように置き換えます。
builder.Services.AddDbContext<CatalogDbContext>( options => options.UseSqlite(builder.Configuration.GetConnectionString("sqlconnection") ?? throw new InvalidOperationException( "Connection string 'sqlconnection' not found.")));
新しい PostgreSQL DbContext で、次の手順を行います。
builder.AddNpgsqlDbContext<CatalogDbContext>("CatalogDB");
アプリは Database.db ファイルを読み取る必要がなくなったため、appsettings.json 内の関連する文字列を削除します。
ソリューション エクスプローラーで、[Catalog.API] の下にある [appsettings.json] を選択します。
ConnectionStrings
エントリを削除すると、ファイルは次のようになります。{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "OpenApi": { "Endpoint": { "Name": "Catalog.API v1" }, "Document": { "Description": "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample", "Title": "eShop - Catalog HTTP API", "Version": "v1" } }, "CatalogOptions": { "PicBasePathFormat": "items/{0}/pic/" } }
[Catalog.Data.Manager] プロジェクトを右クリックし、[削除] を選択します。
ダイアログで [OK] を選択します。
データベース チームは、カタログ データベースの作成とシードに使用する PostgreSQL データベースのバックアップを作成します。 Catalog.API/Seed フォルダー内のバックアップを表示できます。
バインドされたボリュームを使用して PostgreSQL データベースをシードする
AppHost プロジェクトは、PostgreSQL データベース コンテナーを作成し、バインドされたボリュームからデータをシードし、依存関係を挿入して Catalog.API に参照を渡すことができます。
ソリューション エクスプローラーで [eShop.AppHost] プロジェクトを右クリックし、[追加]>[.NET Aspire パッケージ] の順に選択します。
検索ボックスで、末尾に PostgreSQL を追加し、Enter キーを押します。
左側の結果で、[Aspire.Hosting.PostgreSQL] を選択します。
右側でバージョン ドロップダウンを選択し、最新の [8.0.0] リリースを選択します。
[インストール] を選択します。
[変更のプレビュー] ダイアログが表示された場合は、[適用] を選びます。
[ライセンスの同意] ウィンドウで、[同意する] を選択します。
ソリューション エクスプローラーで、[eShop.AppHost] プロジェクトを展開し、[Program.cs] ファイルを開きます。
//Databases
コメントの下に、次のコードを追加します。// Databases var basketStore = builder.AddRedis("BasketStore").WithRedisCommander(); var postgres = builder.AddPostgres("postgres") .WithEnvironment("POSTGRES_DB", "CatalogDB") .WithBindMount("../Catalog.API/Seed", "/docker-entrypoint-initdb.d").WithPgAdmin(); var catalogDB = postgres.AddDatabase("CatalogDB");
上記のコードでは、PostgreSQL データベース コンテナーを作成し、CatalogDB という名前のデータベースを追加し、/docker-entrypoint-initdb.d ディレクトリを ../Catalog.API/Seed ディレクトリにバインドします。 このコードでは、PostgreSQL データベースを管理できる pgAdmin ツール用のコンテナーも作成します。
.WithReference(catalogDB)
を追加して、catalogDB
参照を Catalog.API プロジェクトに渡します。コードは次のようになります。// API Apps var catalogApi = builder.AddProject<Projects.Catalog_API>("catalog-api") .WithReference(catalogDB);
Catalog.Data.Manager プロジェクトは不要になったため、このプロジェクトを AppHost から削除します。 次のコードを削除します。
// DB Manager Apps builder.AddProject<Projects.Catalog_Data_Manager>("catalog-db-mgr");
アプリをテストする
チームは、.NET Aspire を使用したことにより、プロジェクト全体を削除できました。 さらに、カタログ API では、PostgresQL データベース コンテキストを追加するために必要なコードは 1 行だけで済みます。 AppHost の依存関係の挿入とサービス検出は、API が新しいデータベースに接続できるようにするために他のコード変更は必要ないことを意味します。
アプリをコンパイルして起動するには、F5 キーを押すか、[デバッグ] > [デバッグの開始] の順に選択します。
ダッシュボードには、PostgreSQL データベース サーバーと pgAdmin ツールをホストする 2 つの新しいコンテナーがあります。 CatalogDB データベースをホストする PostgreSQL データベース リソースもあります。
pgAdmin を使用して PostgreSQL データベースに接続し、データを調べます。 [postgres pgadmin] エンドポイントを選択します。
[Aspire インスタンス]>[postgres]>[データベース]>[CatalogDB]>[スキーマ]>[カタログ]>[テーブル] の順に展開します。 [Catalog] テーブルを右クリックし、[データの表示/編集]>[最初の 100 行] の順に選択します。
AppHost によって読み込まれたデータが表示されます。
ブラウザーで [eShop リソース] ダッシュボード タブを選択し、[webapp] を選択します。
アプリが開き、以前と同様に動作します。
デバッグを停止するには、Shift+F5 キーを押すか、[デバッグ] > [デバッグの停止] の順に選択します。
アプリに .NET Aspire MongoDB を追加する
現在のアプリでは、顧客の買い物かご用のメモリ内データ ストアとして Redis を使用しています。 チームは、買い物かご用として、より堅牢で耐久性の高いデータ ストアを使用したいと考えています。 Redis Cache を MongoDB データベースに置き換えます。
MongoDB を使用するように Basket.API を変更する
- ソリューション エクスプローラーで Basket.API プロジェクトを右クリックして [追加] を選択し、[追加]>[.NET Aspire パッケージ] の順に選択します。
- 検索ボックスで、末尾に「MongoDB」と入力し、Enter キーを押します。
- Aspire.MongoDB.Driver を選択し、最新の [8.0.0] バージョンを選択します。
- [インストール] を選択します。
- [変更のプレビュー] ダイアログが表示された場合は、[適用] を選びます。
- [ライセンスの同意] ダイアログで、[同意する] を選択します。@
MongoDB 買い物かご用ストアを作成する
買い物かごマイクロサービスは、HostingExtensions
を使用して Redis データ ストアを管理します。 Redis データ ストアを MongoDB データ ストアに置き換えます。
ソリューション エクスプローラーで、[Basket.API] プロジェクト、[ストレージ] フォルダーの順に展開し、[RedisBasketStore.cs] ファイルを選択します。
2 つの非同期メソッド (
GetBasketAsync
とUpdateBasketAsync
) があります。これらは、Redis Cache を使用します。 これらのメソッドの MongoDB バージョンを作成してみましょう。ソリューション エクスプローラーで、[ストレージ] フォルダーを右クリックし、[追加]>[クラス] の順に選択します。
[新しい項目の追加] ダイアログで、ファイルに MongoBasketStore.cs という名前を付け、[追加] を選択します。
MongoBasketStore.cs ファイル内のコードを次のコードに置き換えます。
using eShop.Basket.API.Models; using MongoDB.Driver; using MongoDB.Driver.Linq; namespace eShop.Basket.API.Storage; public class MongoBasketStore { private readonly IMongoCollection<CustomerBasket> _basketCollection; public MongoBasketStore(IMongoClient mongoClient) { // The database name needs to match the created database in the AppHost _basketCollection = mongoClient.GetDatabase("BasketDB").GetCollection<CustomerBasket>("basketitems"); } public async Task<CustomerBasket?> GetBasketAsync(string customerId) { var filter = Builders<CustomerBasket>.Filter.Eq(r => r.BuyerId, customerId); return await _basketCollection.Find(filter).FirstOrDefaultAsync(); } public async Task<CustomerBasket?> UpdateBasketAsync(CustomerBasket basket) { var filter = Builders<CustomerBasket>.Filter.Eq(r => r.BuyerId, basket.BuyerId); var result = await _basketCollection.ReplaceOneAsync(filter, basket, new ReplaceOptions { IsUpsert = true }); return result.IsModifiedCountAvailable ? basket : null; } }
上記のコードでは、
CustomerBasket
モデルで動作するMongoBasketStore
クラスを作成します。 このコレクションは、MongoDB データベース内の顧客の買い物かごに対する CRUD 操作を処理します。ソリューション エクスプローラーで、[Basket.API]>[拡張機能] の順に展開し、[HostingExtensions.cs] ファイルを選択します。
Redis コードを置き換えます。
builder.AddRedis("BasketStore"); builder.Services.AddSingleton<RedisBasketStore>();
MongoDB コードで、次の手順を行います。
builder.AddMongoDBClient("BasketDB"); builder.Services.AddSingleton<MongoBasketStore>();
ソリューション エクスプローラーで、[Grpc] フォルダーを展開し、[BasketService.cs] ファイルを開きます。
MongoBasketStore
を受け入れるようにクラスを変更し、次のように置き換えます。public class BasketService(RedisBasketStore basketStore) : Basket.BasketBase
置換後のコード:
public class BasketService(MongoBasketStore basketStore) : Basket.BasketBase
MongoDB データベースを AppHost に追加する
ソリューション エクスプローラーで、[eShop.AppHost] プロジェクトを右クリックし、[追加]>[.NET Aspire パッケージ] の順に選択します。
検索ボックスで、末尾に「MongoDB」と入力し、Enter キーを押します。
[Aspire.Hosting.MongoDB] パッケージを選択し、最新の [8.0.0] バージョンを選択します。
[インストール] を選択します。
[変更のプレビュー] ダイアログが表示された場合は、[適用] を選びます。
[ライセンスの同意] ダイアログで、[同意する] を選択します。@
ソリューション エクスプローラーで、[eShop.AppHost] プロジェクトを展開し、[Program.cs] ファイルを開きます。
[データベース] セクションで MongoDB コンポーネントを追加します。
var mongo = builder.AddMongoDB("mongo") .WithMongoExpress() .AddDatabase("BasketDB");
上記のコードでは、MongoDB データベース コンテナーを作成し、BasketDB という名前のデータベースを追加します。 このコードでは、MongoDB データベースを管理できる Mongo Express ツール用のコンテナーも作成します。
Redis コンテナーを削除します。
var basketStore = builder.AddRedis("BasketStore").WithRedisCommander();
コードは、次のようになります。
// Databases var postgres = builder.AddPostgres("postgres") .WithEnvironment("POSTGRES_DB", "CatalogDB") .WithBindMount("../Catalog.API/Seed", "/docker-entrypoint-initdb.d") .WithPgAdmin(); var catalogDB = postgres.AddDatabase("CatalogDB"); var mongo = builder.AddMongoDB("mongo") .WithMongoExpress() .AddDatabase("BasketDB");
Basket.API プロジェクトには新しい MongoDB データベースへの参照が必要であり、Redis 参照は削除する必要があります。
var basketApi = builder.AddProject<Projects.Basket_API>("basket-api") .WithReference(mongo) .WithReference(idp);
これで、Basket.API プロジェクトは、MongoDB データベースを使用する準備ができました。 アプリをテストして、動作するかどうかを確認してみましょう。
アプリをテストする
アプリをコンパイルして起動するには、F5 キーを押すか、[デバッグ] > [デバッグの開始] の順に選択します。
ダッシュボードに新しい MongoDB コンテナーが表示されます。一方はデータベース サーバー用で、もう一方は MongoDB Express 用です。 また、新しい MongoDBDatabase リソースもあります。これらは、BasketDB データベースをホストします。
[webapp] エンドポイントを選択します。
テスト ユーザーの資格情報を使用してサインインするには、右上のユーザー アイコンを選択します。 メールは test@example.com で、パスワードは P@$$w0rd1 です。
ホーム ページから [Adventurer GPS Watch] を選択します。
[ショッピング カートに追加] を選択すると、例外が表示されます。
アプリをデバッグする
品目を買い物かごに追加しようとすると、アプリによって例外がスローされます。 ダッシュボードを使用すると、この問題をデバッグするのに役立ちます。
ブラウザーで [eShop リソース] ダッシュボード タブを選択します。
ダッシュボードには、basket-api と webapp のエラーが表示されます。 basket-api のログを確認します。
basket-api リソースの [ログ] 列で、[表示] を選択します。
例外があります。
System.FormatException: Element '_id' does not match any field or property of class eShop.Basket.API.Models.CustomerBasket.
[リソース] メニュー項目を選択し、[mongo-mongoexpress] エンドポイントを選択します。
[データベース] セクションで、[BasketDB] の横にある [表示] を選択します。
[コレクション] で、[basketitems] の横にある [表示] を選択します。
MongoDB に格納されているドキュメントには、_id フィールドがあります。 MongoDB コレクションに格納されるすべてのドキュメントには、一意の _id フィールドが必要です。
デバッグを停止するには、Shift+F5 キーを押すか、[デバッグ] > [デバッグの停止] の順に選択します。
コードを確認し、問題を修正する
CustomerBasket を調べて、問題が見つかるかどうか確認しましょう。
ソリューション エクスプローラーで、[Basket.API]>[モデル] フォルダーの順に展開し、[CustomerBasket.cs] ファイルを開きます。
public class CustomerBasket { public required string BuyerId { get; set; } public List<BasketItem> Items { get; set; } = []; }
CustomerBasket モデルには、_id フィールドと一致するフィールドまたはプロパティはありません。 Entity Framework は _id フィールドを CustomerBasket モデルにマップしようとしますが、一致が見つかりません。
_id フィールドが含まれるように
CustomerBasket
モデルを更新します。public class CustomerBasket { /// <summary> /// MongoDB document identifier /// </summary> public string _id { get; set; } = ""; public required string BuyerId { get; set; } public List<BasketItem> Items { get; set; } = []; }
修正されたアプリをテストする
アプリをコンパイルして起動するには、F5 キーを押すか、[デバッグ] > [デバッグの開始] の順に選択します。
[webapp] の [エンドポイント] 列で URL を右クリックし、[InPrivate ウィンドウでリンクを開く] を選択します。
InPrivate ウィンドウを使用すると、ブラウザーで認証に前のセッション Cookie を使用しないことが保証されます。
テスト ユーザーの資格情報を使用してサインインするには、右上のユーザー アイコンを選択します。 メールは test@example.com で、パスワードは P@$$w0rd1 です。
ホーム ページから [Adventurer GPS Watch] を選択します。
[ショッピング カートに追加] を選択します。
Northern Mountains アプリの買い物かご機能が機能するようになりました。
SQLite データベースは PostgreSQL に正常に置き換えられ、Redis Cache は MongoDB データベースに正常に置き換えられました。 .NET Aspire を使用して、データベースを管理し、その中のデータを調べました。また、ダッシュボードを使用してアプリの問題をデバッグすることもできました。