チュートリアル: Azure Cosmos DB for NoSQL で ASP.NET Web アプリケーションを開発する
適用対象: NoSQL
Azure SDK for .NET を使用すると、 C# の LINQ またはSQL クエリ文字列 を使用して、NoSQL 用 API コンテナー内のデータ に対してクエリを実行できます。 このチュートリアルでは、プレースホルダー データを使用して API からクエリを実行する既存の ASP.NET Web アプリケーションを更新するプロセスについて説明します。
このチュートリアルでは、次の作業を行う方法について説明します。
- NoSQL 用 API を使用してデータベースとコンテナーを作成して設定する
- テンプレートから ASP.NET Web アプリケーションを作成する
- Azure SDK for .NET を使用して NoSQL 用 API コンテナーからデータを照会する
前提条件
- 既存の Azure Cosmos DB for NoSQL アカウント。
- Azure サブスクリプションを既にお持ちの場合は、新しいアカウントを作成します。
- Azure サブスクリプションがない場合。 Azure Cosmos DB を無料で試すことができます。クレジット カードは必要ありません。
- Visual Studio Code
- .NET 6 (LTS) 以降
- C# アプリケーションの作成経験。
NoSQL リソース用 API を作成する
まず、既存の NoSQL 用 API アカウントにデータベースとコンテナーを作成します。 その後、cosmicworks
dotnet ツールを使用して、このアカウントにデータを設定します。
Azure portal で既存の NoSQL 用 API アカウントに移動します。
[リソース] メニューで [キー] を選択します。
[キー] ページで、[プライマリ接続文字列]* フィールドの値を確認して記録します。 この値は、チュートリアル全体で使われます。
リソース メニューで [Data Explorer] を選びます。
[データ エクスプローラー] ページで、コマンド バーの [新しいコンテナー] オプションを選択します。
[ 新しいコンテナー] ダイアログで、次の設定で新しいコンテナーを作成します。
設定 値 データベース ID cosmicworks
データベースのスループットの種類 [手動] データベースのスループットの量 1000
コンテナー ID products
パーティション キー /category/name
重要
このチュートリアルでは、まず共有スループットでデータベースを 1,000 RU/秒までスケールアップして、データ移行のパフォーマンスを最大にします。 データの移行が完了したら、プロビジョニングされたスループットを 400 RU/秒にスケールダウンします。
[OK] を選択してコンテナーとデータベースを作成します。
ターミナルを開いてコマンドを実行し、コンテナーにデータを設定します。
ヒント
必要に応じて、Azure Cloud Shell を使用することもできます。
NuGet から
cosmicworks
dotnet ツールの v2 をインストールします。dotnet tool install --global cosmicworks --version 2.*
この
cosmicworks
ツールを使用して、このラボで前に記録した URI と PRIMARY KEY 値を使用して、NoSQL 用 API アカウントにサンプル製品データを設定します。 これらの記録された値は、endpoint
パラメーターとkey
パラメーターにそれぞれ使用されます。cosmicworks \ --number-of-products 1759 \ --number-of-employees 0 \ --disable-hierarchical-partition-keys \ --connection-string <nosql-connection-string>
コマンド ライン ツールからの出力を確認します。 コンテナーに 1,759 個の項目を追加する必要があります。 含まれる出力例は、簡潔にするために切り捨てられます。
── Parsing connection string ──────────────────────────────────────────────────────────────── ╭─Connection string──────────────────────────────────────────────────────────────────────────╮ │ AccountEndpoint=https://<account-name>.documents.azure.com:443/;AccountKey=<account-key>; │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ── Populating data ────────────────────────────────────────────────────────────────────────── ╭─Products configuration─────────────────────────────────────────────────────────────────────╮ │ Database cosmicworks │ │ Container products │ │ Count 1,759 │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ... [SEED] 00000000-0000-0000-0000-000000005951 | Road-650 Black, 60 - Bikes [SEED] 00000000-0000-0000-0000-000000005950 | Mountain-100 Silver, 42 - Bikes [SEED] 00000000-0000-0000-0000-000000005949 | Men's Bib-Shorts, L - Clothing [SEED] 00000000-0000-0000-0000-000000005948 | ML Mountain Front Wheel - Components [SEED] 00000000-0000-0000-0000-000000005947 | Mountain-500 Silver, 42 - Bikes
アカウントの [データ エクスプローラー] ページに戻ります。
[データ] セクションで、データベース ノードを
cosmicworks
展開し、[スケール] を選択します。スループットを 1,000 から 400 に減らします。
コマンド バーの [保存] を選択します。
[データ] セクションで、 products コンテナー ノードを展開して選択します。
コマンド バーで、 [新規 SQL クエリ]を選択します。
クエリ エディターで、この SQL クエリ文字列を追加します。
SELECT p.sku, p.price FROM products p WHERE p.price < 2000 ORDER BY p.price DESC
[クエリの実行] を選択してクエリを実行し、結果を確認します。
結果は、コンテナー内の
price
値が2,000 未満のすべての項目をページ分割された配列で、 最高値から最低の値に並べ替える必要があります。 簡潔にするために、出力のサブセットをここに含めます。[ { "sku": "BK-R79Y-48", "price": 1700.99 }, ... { "sku": "FR-M94B-46", "price": 1349.6 }, ...
クエリ エディターの内容をこのクエリに置き換え、もう一度 [クエリの実行] を選択して結果を確認します。
SELECT p.name, p.category.name AS category, p.category.subCategory.name AS subcategory, p.tags FROM products p JOIN tag IN p.tags WHERE STRINGEQUALS(tag, "yellow", true)
結果は、 名前 値 が
Tag-32
のタグが少なくとも 1 つ含まれる項目のみを含むようにフィルター処理された項目の小さな配列である必要があります。 ここでも、簡潔にするために、出力のサブセットがここに含まれています。[ ... { "name": "HL Touring Frame - Yellow, 60", "category": "Components", "subcategory": "Touring Frames", "tags": [ "Components", "Touring Frames", "Yellow", "60" ] }, ... ]
ASP.NET Web アプリケーションの作成
次に、サンプル プロジェクト テンプレートを使用して新しい ASP.NET Web アプリケーションを作成します。 次に、ソース コードを調べ、サンプルを実行してアプリケーションを理解してから、Azure SDK for .NET を使用して Azure Cosmos DB 接続を追加します。
重要
このチュートリアルでは、NuGet からパッケージを透過的にプルします。 dotnet nuget list source
を使用して、パッケージ ソースを確認できます。 パッケージ ソースとして NuGet がない場合は、dotnet nuget add source
を使用してサイトをソースとしてインストールします。
空のディレクトリでターミナルを開きます。
NuGet から
cosmicworks.template.web
プロジェクト テンプレート パッケージをインストールします。dotnet new install cosmicworks.template.web
新しくインストールされた
dotnet new cosmosdbnosql-webapp
テンプレートを使用して、新しい Web アプリケーション プロジェクトを 作成します。dotnet new cosmosdbnosql-webapp
Web アプリケーション プロジェクトをビルドして実行します。
dotnet run
実行コマンドからの出力を確認します。 出力には、アプリケーションが実行されているポートと URL の一覧が含まれている必要があります。
... info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Production ...
新しいブラウザー ウィンドウを開き、実行中の Web アプリケーションに移動します。 実行中のアプリケーションの 3 つのページすべてを確認します。
実行中のプロセスを終了して、実行中のアプリケーションを停止します。
ヒント
実行中のプロセスを停止するには、 Ctrl+C コマンドを使用します。または、ターミナルを閉じてもう一度開く方法もあります。
現在のプロジェクト フォルダーをワークスペースとして使用して Visual Studio Code を開きます。
ヒント
ターミナルで を
code .
を実行して Visual Studio Code を開き、現在のワークスペースとして作業ディレクトリを自動的に開くことができます。Services/ICosmosService.cs ファイルに移動して開きます。
RetrieveActiveProductsAsync
およびRetrieveAllProductsAsync
の既定のメソッドの実装を確認します。 これらのメソッドは、プロジェクトを初めて実行するときに使用する製品の静的リストを作成します。 ここでは、いずれかのメソッドの切り捨てられた例を示します。public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync() { await Task.Delay(1); return new List<Product>() { new Product(id: "baaa4d2d-5ebe-45fb-9a5c-d06876f408e0", category: new Category(name: "Components, Road Frames"), sku: "FR-R72R-60", name: """ML Road Frame - Red, 60""", description: """The product called "ML Road Frame - Red, 60".""", price: 594.83000000000004m), new Product(id: "bd43543e-024c-4cda-a852-e29202310214", category: new Category(name: "Components, Forks"), sku: "FK-5136", name: """ML Fork""", description: """The product called "ML Fork".""", price: 175.49000000000001m), ... }; }
Services/CosmosService.cs ファイルに移動し、開きます。 CosmosService クラスの現在の実装を確認します。 このクラスは ICosmosService インターフェイスを実装しますが、メソッドはオーバーライドしません。 このコンテキストでは、 クラスは、実装のオーバーライドが インターフェイスで提供されるまで、既定のインターフェイス実装を使用します。
public class CosmosService : ICosmosService { }
最後に、Models/Product.cs と Models/Category.cs ファイルに移動して開きます。 各ファイルで定義されているレコードの型を確認します。 これらの型は、このチュートリアル全体のクエリで使われます。
public record Product( string id, Category category, string sku, string name, string description, decimal price );
public record Category( string name );
.NET SDK を使用してデータのクエリを実行する
次に、このサンプル プロジェクトに Azure SDK for .NET を追加し、ライブラリを使用して、NoSQL コンテナー用 API のデータに対してクエリを実行します。
ターミナルに戻り、NuGet から
Microsoft.Azure.Cosmos
パッケージを追加します。dotnet add package Microsoft.Azure.Cosmos
プロジェクトをビルドします。
dotnet build
Visual Studio Code に戻り、もう一度 Services/CosmosService.cs ファイルに移動します。
Microsoft.Azure.Cosmos
とMicrosoft.Azure.Cosmos.Linq
名前空間のための新しい using ディレクティブを追加します。using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Linq;
CosmosService クラス内で、
_client
という名前のCosmosClient
型の新しいprivate readonly
メンバーを追加します。private readonly CosmosClient _client;
CosmosService
クラスの新しい空のコンストラクターを作成します。public CosmosService() { }
このコンストラクター内で、
CosmosClient
クラスの新しいインスタンスを作成し、ラボで前に記録した PRIMARY CONNECTION STRING の値を含む文字列パラメーターを渡します。 この新しいインスタンスを_client
メンバーに保存します。public CosmosService() { _client = new CosmosClient( connectionString: "<primary-connection-string>" ); }
CosmosService クラス内に戻り、
container
という名前のContainer
型の新しいprivate
プロパティを作成します。cosmicworks
データベースとproducts
コンテナーを返すように get アクセサー を設定します。private Container container { get => _client.GetDatabase("cosmicworks").GetContainer("products"); }
IEnumerable<Product>
を返す という名前RetrieveAllProductsAsync
の新しい非同期メソッドを 作成します。public async Task<IEnumerable<Product>> RetrieveAllProductsAsync() { }
次の手順では、
RetrieveAllProductsAsync
メソッド内にこのコードを追加します。GetItemLinqQueryable<>
ジェネリック メソッドを使用して、言語統合クエリ (LINQ) の構築に使用できる型IQueryable<>
のオブジェクトを取得します。 そのオブジェクトをqueryable
という名前の変数に保存します。var queryable = container.GetItemLinqQueryable<Product>();
Where
およびOrderByDescending
拡張メソッドを使用して LINQ クエリを作成します。ToFeedIterator
拡張メソッドを使用して、Azure Cosmos DB からデータを取得し、feed
という名前の変数に反復子を格納する反復子を作成します。 この式全体を using ステートメントでラップして、後で反復子を破棄します。using FeedIterator<Product> feed = queryable .Where(p => p.price < 2000m) .OrderByDescending(p => p.price) .ToFeedIterator();
ジェネリック
List<>
型を使用して、results
という名前の新しい変数を作成します。List<Product> results = new();
feed
変数のHasMoreResults
プロパティが falseを返すまで反復処理を行う while ループを作成します。 このループにより、サーバー側の結果のすべてのページをループ処理できます。while (feed.HasMoreResults) { }
while ループ内で、
feed
変数のReadNextAsync
メソッドを非同期的に呼び出し、その結果をresponse
という名前の変数に保存します。while (feed.HasMoreResults) { var response = await feed.ReadNextAsync(); }
引き続き while ループ内で、foreach ループを使用して応答の各項目を通過し、
results
リストに追加します。while (feed.HasMoreResults) { var response = await feed.ReadNextAsync(); foreach (Product item in response) { results.Add(item); } }
RetrieveAllProductsAsync
メソッドの出力としてresults
リストを返します。return results;
IEnumerable<Product>
を返す という名前RetrieveActiveProductsAsync
の新しい非同期メソッドを 作成します。public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync() { }
次の手順では、
RetrieveActiveProductsAsync
メソッド内にこのコードを追加します。SQL クエリで
sql
という名前の新しい文字列を作成し、フィルター (@tagFilter
) が各項目の タグ 配列に適用される複数のフィールドを取得します。string sql = """ SELECT p.id, p.name, p.category, p.sku, p.description, p.price FROM products p JOIN tag IN p.tags WHERE STRINGEQUALS(tag, @tagFilter, true) """;
query
という名前の新しいQueryDefinition
変数を作成し、唯一のクエリ パラメーターとしてsql
文字列を渡します。 また、WithParameter
fluid メソッドを使用して、red
の値を@tagFilter
パラメーターに適用します。var query = new QueryDefinition( query: sql ) .WithParameter("@tagFilter", "red");
GetItemQueryIterator<>
ジェネリック メソッドとquery
変数を使用して、Azure Cosmos DB からデータを取得する反復子を作成します。 この反復子をfeed
という名前の変数として保存します。 この式全体を using ステートメントでラップして、後で反復子を破棄します。using FeedIterator<Product> feed = container.GetItemQueryIterator<Product>( queryDefinition: query );
while ループを使用して複数のページの結果を反復処理し、その値を汎用
List<>
の名前付き 結果 に格納します。RetrieveActiveProductsAsync
メソッドの出力として 結果 を返します。List<Product> results = new(); while (feed.HasMoreResults) { FeedResponse<Product> response = await feed.ReadNextAsync(); foreach (Product item in response) { results.Add(item); } } return results;
Services/CosmosClient.cs ファイルを保存します。
ヒント
コードが正しいかどうかわからない場合は、GitHub の サンプル コード に照らしてソース コードを確認できます。
最終的なアプリケーションを検証する
最後に、 ホット リロード を有効にしてアプリケーションを実行します。 アプリケーションを実行すると、コードが NoSQL 用 API からデータにアクセスできることを検証します。
ターミナルに戻り、アプリケーションを実行します。
dotnet run
run コマンドの出力には、アプリケーションが実行されているポートと URL の一覧が含まれている必要があります。 新しいブラウザー ウィンドウを開き、実行中の Web アプリケーションに移動します。 実行中のアプリケーションの 3 つのページすべてを確認します。 各ページには、Azure Cosmos DB からのライブ データが含まれるようになりました。
リソースをクリーンアップする
このチュートリアルで使用したデータベースが不要になったら、削除してください。 これを行うには、アカウント ページに移動し、[データ エクスプローラー] を選択し、cosmicworks
データベースを選択して、[削除] を選択します。
次のステップ
Azure Cosmos DB を使用して初めての .NET Web アプリケーションを作成したので、SDK の詳細を確認して、より多くのデータをインポートし、複雑なクエリを実行し、Azure Cosmos DB for NoSQL リソースを管理できるようになりました。