チュートリアル: 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 コンテナーからデータを照会する

前提条件

NoSQL リソース用 API を作成する

まず、既存の NoSQL 用 API アカウントにデータベースとコンテナーを作成します。 その後、cosmicworks dotnet ツールを使用して、このアカウントにデータを設定します。

  1. Azure portal で既存の NoSQL 用 API アカウントに移動します。

  2. [リソース] メニューで [キー] を選択します。

    NoSQL 用 API アカウント ページのスクリーンショット。リソース メニューで [キー] オプションが強調表示されています。

  3. [キー] ページで、 URIPRIMARY KEYPRIMARY CONNECTION STRING* フィールドの値を確認して記録します。 これらの値は、チュートリアル全体で使用されます。

    URI、主キー、プライマリ接続文字列の各フィールドが強調表示されている [キー] ページのスクリーンショット。

  4. リソース メニューで [Data Explorer] を選びます。

    リソース メニューで強調表示されている [データ エクスプローラー] オプションのスクリーンショット。

  5. [データ エクスプローラー] ページで、コマンド バーの [新しいコンテナー] オプションを選択します。

    データ エクスプローラー コマンド バーの [新しいコンテナー] オプションのスクリーンショット。

  6. [ 新しいコンテナー] ダイアログで、次の設定で新しいコンテナーを作成します。

    設定
    データベース ID cosmicworks
    データベースのスループットの種類 [手動]
    データベースのスループットの量 4000
    コンテナー ID products
    パーティション キー /categoryId

    データ エクスプローラーの [新しいコンテナー] ダイアログのスクリーンショット。各フィールドにさまざまな値が表示されています。

    重要

    このチュートリアルでは、まず共有スループットで最大 4,000 RU/秒のデータベースをスケーリングし、データ移行のパフォーマンスを最大化します。 データの移行が完了したら、プロビジョニングされたスループットを 400 RU/秒にスケールダウンします。

  7. [OK] を選択してコンテナーとデータベースを作成します。

  8. ターミナルを開いてコマンドを実行し、コンテナーにデータを設定します。

    ヒント

    必要に応じて、Azure Cloud Shell を使用することもできます。

  9. NuGet から cosmicworks dotnet ツールの プレリリース バージョンをインストールします。

    dotnet tool install --global cosmicworks  --prerelease
    
  10. この cosmicworks ツールを使用して、このラボで前に記録した URIPRIMARY KEY 値を使用して、NoSQL 用 API アカウントにサンプル製品データを設定します。 これらの記録された値は、endpoint パラメーターと key パラメーターにそれぞれ使用されます。

    cosmicworks \
        --datasets product \
        --endpoint <uri> \
        --key <primary-key>
    
  11. コマンド ライン ツールからの出力を確認します。 コンテナーに 200 個を超える項目を追加する必要があります。 含まれる出力例は、簡潔にするために切り捨てられます。

    ...
    Revision:       v4
    Datasets:
            product
    
    Database:       [cosmicworks]   Status: Created
    Container:      [products]      Status: Ready
    
    product Items Count:    295
    Entity: [9363838B-2D13-48E8-986D-C9625BE5AB26]  Container:products      Status: RanToCompletion
    ...
    Container:      [product]       Status: Populated
    
  12. アカウントの [データ エクスプローラー] ページに戻ります。

  13. [データ] セクションで、データベース ノードを cosmicworks 展開し、[スケール] を選択します。

    データベース ノード内の [スケール] オプションのスクリーンショット。

  14. スループットを 4,000 から 400 に減らします。

    データベースのスループット設定が 400 RU/秒に減ったスクリーンショット。

  15. コマンド バーの [保存] を選択します。

    データ エクスプローラー コマンド バーの [保存] オプションのスクリーンショット。

  16. [データ] セクションで、 products コンテナー ノードを展開して選択します。

    データベース ノード内の展開されたコンテナー ノードのスクリーンショット。

  17. コマンド バーで、 [新規 SQL クエリ]を選択します。

    データ エクスプローラー コマンド バーの [新規 SQL クエリ] オプションのスクリーンショット。

  18. クエリ エディターで、この SQL クエリ文字列を追加します。

    SELECT
      p.sku,
      p.price
    FROM products p
    WHERE p.price < 2000
    ORDER BY p.price DESC
    
  19. [クエリの実行] を選択してクエリを実行し、結果を確認します。

    データ エクスプローラー コマンド バーの [クエリの実行] オプションのスクリーンショット。

  20. 結果は、コンテナー内の price 値が2,000 未満のすべての項目をページ分割された配列で、 最高値から最低の値に並べ替える必要があります。 簡潔にするために、出力のサブセットをここに含めます。

    [
      {
        "sku": "BK-R79Y-48",
        "price": 1700.99
      },
      ...
      {
        "sku": "FR-M94B-46",
        "price": 1349.6
      },
    ...
    
  21. クエリ エディターの内容をこのクエリに置き換え、もう一度 [クエリの実行] を選択して結果を確認します。

    SELECT
      p.name,
      p.categoryName,
      p.tags
    FROM products p
    JOIN t IN p.tags
    WHERE t.name = "Tag-32"
    
  22. 結果は、 名前 値 がTag-32 のタグが少なくとも 1 つ含まれる項目のみを含むようにフィルター処理された項目の小さな配列である必要があります。 ここでも、簡潔にするために、出力のサブセットがここに含まれています。

    ...
    {
    "name": "ML Mountain Frame - Black, 44",
    "categoryName": "Components, Mountain Frames",
    "tags": [
        {
        "id": "18AC309F-F81C-4234-A752-5DDD2BEAEE83",
        "name": "Tag-32"
        }
    ]
    },
    ...
    

ASP.NET Web アプリケーションの作成

次に、サンプル プロジェクト テンプレートを使用して新しい ASP.NET Web アプリケーションを作成します。 次に、ソース コードを調べ、サンプルを実行してアプリケーションを理解してから、Azure SDK for .NET を使用して Azure Cosmos DB 接続を追加します。

  1. 空のディレクトリでターミナルを開きます。

  2. NuGet から cosmicworks.template.web プロジェクト テンプレート パッケージをインストールします。

    dotnet new install cosmicworks.template.web
    
  3. 新しくインストールされた dotnet new cosmosdbnosql-webapp テンプレートを使用して、新しい Web アプリケーション プロジェクトを 作成します。

    dotnet new cosmosdbnosql-webapp
    
  4. Web アプリケーション プロジェクトをビルドして実行します。

    dotnet run
    
  5. 実行コマンドからの出力を確認します。 出力には、アプリケーションが実行されているポートと 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
    ...
    
  6. 新しいブラウザー ウィンドウを開き、実行中の Web アプリケーションに移動します。 実行中のアプリケーションの 3 つのページすべてを確認します。

    プレースホルダー データを使用して実行されているサンプル Web アプリケーションのスクリーンショット。

  7. 実行中のプロセスを終了して、実行中のアプリケーションを停止します。

    ヒント

    実行中のプロセスを停止するには、 Ctrl+C コマンドを使用します。または、ターミナルを閉じてもう一度開く方法もあります。

  8. 現在のプロジェクト フォルダーをワークスペースとして使用して Visual Studio Code を開きます。

    ヒント

    ターミナルで を code . を実行して Visual Studio Code を開き、現在のワークスペースとして作業ディレクトリを自動的に開くことができます。

  9. 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", categoryId: "3E4CEACD-D007-46EB-82D7-31F6141752B2", categoryName: "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: "d5928182-0307-4bf9-8624-316b9720c58c", categoryId: "AA5A82D4-914C-4132-8C08-E7B75DCE3428", categoryName: "Components, Cranksets", sku: "CS-6583", name: """ML Crankset""", description: """The product called "ML Crankset".""", price: 256.49000000000001m)
        };
    }
    
  10. Services/CosmosService.cs ファイルに移動し、開きます。 CosmosService クラスの現在の実装を確認します。 このクラスは ICosmosService インターフェイスを実装しますが、メソッドはオーバーライドしません。 このコンテキストでは、 クラスは、実装のオーバーライドが インターフェイスで提供されるまで、既定のインターフェイス実装を使用します。

    public class CosmosService : ICosmosService
    { }
    
  11. 最後に、 Models/Product.cs ファイルに移動して開きます。 このファイルで定義されているレコードの種類を確認します。 この種類は、このチュートリアル全体のクエリで使用されます。

    public record Product(
        string id,
        string categoryId,
        string categoryName,
        string sku,
        string name,
        string description,
        decimal price
    );
    

.NET SDK を使用してデータのクエリを実行する

次に、このサンプル プロジェクトに Azure SDK for .NET を追加し、ライブラリを使用して、NoSQL コンテナー用 API のデータに対してクエリを実行します。

  1. ターミナルに戻り、NuGet から Microsoft.Azure.Cosmos パッケージを追加します。

    dotnet add package Microsoft.Azure.Cosmos
    
  2. プロジェクトをビルドします。

    dotnet build
    
  3. Visual Studio Code に戻り、もう一度 Services/CosmosService.cs ファイルに移動します。

  4. Microsoft.Azure.CosmosMicrosoft.Azure.Cosmos.Linq 名前空間のための新しい using ディレクティブを追加します。

    using Microsoft.Azure.Cosmos;
    using Microsoft.Azure.Cosmos.Linq;
    
  5. CosmosService クラス内で、 _client という名前のCosmosClient 型の新しい private readonly メンバーを追加します。

    private readonly CosmosClient _client;
    
  6. CosmosClient クラスの新しい空のコンストラクターを作成します。

    public CosmosClient()
    { }
    
  7. このコンストラクター内で、CosmosClient クラスの新しいインスタンスを作成し、ラボで前に記録した PRIMARY CONNECTION STRING の値を含む文字列パラメーターを渡します。 この新しいインスタンスを _client メンバーに保存します。

    public CosmosClient()
    { 
        _client = new CosmosClient(
            connectionString: "<primary-connection-string>"
        );
    }
    
  8. CosmosClient クラス内に戻り、 container という名前の Container 型の新しい private プロパティを作成します。 cosmicworks データベースと products コンテナーを返すように get アクセサー を設定します。

    private Container container
    {
        get => _client.GetDatabase("cosmicworks").GetContainer("products");
    }
    
  9. IEnumerable<Product> を返す という名前 RetrieveAllProductsAsync の新しい非同期メソッドを 作成します。

    public async Task<IEnumerable<Product>> RetrieveAllProductsAsync()
    { }
    
  10. 次の手順では、RetrieveAllProductsAsync メソッド内にこのコードを追加します。

    1. GetItemLinqQueryable<> ジェネリック メソッドを使用して、言語統合クエリ (LINQ) の構築に使用できる型 IQueryable<> のオブジェクトを取得します。 そのオブジェクトを queryable という名前の変数に保存します。

      var queryable = container.GetItemLinqQueryable<Product>();
      
    2. Where および OrderByDescending 拡張メソッドを使用して LINQ クエリを作成します。 ToFeedIterator 拡張メソッドを使用して、Azure Cosmos DB からデータを取得し、 feed という名前の変数に反復子を格納する反復子を作成します。 この式全体を using ステートメントでラップして、後で反復子を破棄します。

      using FeedIterator<Product> feed = queryable
          .Where(p => p.price < 2000m)
          .OrderByDescending(p => p.price)
          .ToFeedIterator();
      
    3. ジェネリック List<> 型を使用して、results という名前の新しい変数を作成します。

      List<Product> results = new();
      
    4. feed 変数の HasMoreResults プロパティが falseを返すまで反復処理を行う while ループを作成します。 このループにより、サーバー側の結果のすべてのページをループ処理できます。

      while (feed.HasMoreResults)
      { }
      
    5. while ループ内で、feed 変数の ReadNextAsync メソッドを非同期的に呼び出し、その結果を response という名前の変数に保存します。

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
      }
      
    6. 引き続き while ループ内で、foreach ループを使用して応答の各項目を通過し、results リストに追加します。

      while (feed.HasMoreResults)
      {
          var response = await feed.ReadNextAsync();
          foreach (Product item in response)
          {
              results.Add(item);
          }
      }
      
    7. RetrieveAllProductsAsync メソッドの出力として results リストを返します。

      return results;
      
  11. IEnumerable<Product> を返す という名前 RetrieveActiveProductsAsync の新しい非同期メソッドを 作成します。

    public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync()
    { }
    
  12. 次の手順では、RetrieveActiveProductsAsync メソッド内にこのコードを追加します。

    1. SQL クエリで sql という名前の新しい文字列を作成し、フィルター (@tagFilter) が各項目の タグ 配列に適用される複数のフィールドを取得します。

      string sql = """
      SELECT
          p.id,
          p.categoryId,
          p.categoryName,
          p.sku,
          p.name,
          p.description,
          p.price,
          p.tags
      FROM products p
      JOIN t IN p.tags
      WHERE t.name = @tagFilter
      """;
      
    2. query という名前の新しい QueryDefinition 変数を作成し、唯一のクエリ パラメーターとして sql 文字列を渡します。 また、WithParameter fluid メソッドを使用して、Tag-75 の値を @tagFilter パラメーターに適用します。

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@tagFilter", "Tag-75");
      
    3. GetItemQueryIterator<> ジェネリック メソッドと query 変数を使用して、Azure Cosmos DB からデータを取得する反復子を作成します。 この反復子を feed という名前の変数として保存します。 この式全体を using ステートメントでラップして、後で反復子を破棄します。

      using FeedIterator<Product> feed = container.GetItemQueryIterator<Product>(
          queryDefinition: query
      );
      
    4. 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;
      
  13. Services/CosmosClient.cs ファイルを保存します

    ヒント

    コードが正しいかどうかわからない場合は、GitHub の サンプル コード に照らしてソース コードを確認できます。

最終的なアプリケーションを検証する

最後に、 ホット リロード を有効にしてアプリケーションを実行します。 アプリケーションを実行すると、コードが NoSQL 用 API からデータにアクセスできることを検証します。

  1. ターミナルに戻り、アプリケーションを実行します。

    dotnet watch
    

    注意

    dotnet watch はここで有効になっているので、間違いが見つかるとコードをすばやく変更できます。

  2. run コマンドの出力には、アプリケーションが実行されているポートと URL の一覧が含まれている必要があります。 新しいブラウザー ウィンドウを開き、実行中の Web アプリケーションに移動します。 実行中のアプリケーションの 3 つのページすべてを確認します。 各ページには、Azure Cosmos DB からのライブ データが含まれるようになりました。

リソースをクリーンアップする

このチュートリアルで使用したデータベースが不要になったら、削除してください。 これを行うには、アカウント ページに移動し、[データ エクスプローラー] を選択し、cosmicworks データベースを選択して、[削除] を選択します。

次のステップ

Azure Cosmos DB を使用して初めての .NET Web アプリケーションを作成したので、SDK の詳細を確認して、より多くのデータをインポートし、複雑なクエリを実行し、Azure Cosmos DB for NoSQL リソースを管理できるようになりました。