教學課程:透過 Azure Cosmos DB for NoSQL 開發 ASP.NET Web 應用程式

適用於:NoSQL

適用於 .NET 的 Azure SDK 可讓您使用 C# 中的 LINQSQL 查詢字串,查詢 API for NoSQL 容器中的資料。 本教學課程將逐步解說如何更新使用預留位置資料的現有 ASP.NET Web 應用程式,以改為從 API 查詢。

在本教學課程中,您會了解如何:

  • 使用 API for NoSQL 建立和填入資料庫和容器
  • 從範本建立 ASP.NET Web 應用程式
  • 使用適用於 .NET 的 Azure SDK 從 API for NoSQL 容器查詢資料

必要條件

建立 API for NoSQL 資源

首先,您會在現有的 API for NoSQL 帳戶中建立資料庫和容器。 接著,您將使用 cosmicworks dotnet 工具在此帳戶中填入資料。

  1. Azure 入口網站中瀏覽至您現有的 API for NoSQL 帳戶。

  2. 在 [資源] 功能表中,選取 [金鑰]

    適用於 NoSQL 帳戶的 API 頁面螢幕快照。[金鑰] 選項會在資源選單中反白顯示。

  3. 在 [金鑰] 頁面上,觀察並記錄 [主要連接字串] 字段的值。 在整個教學課程中,將會使用此值。

    [金鑰] 頁面的螢幕快照,其中已醒目提示 [URI]、[主鍵] 和 [主要 連線 字串] 字段。

  4. 在 [資源] 功能表中,選取 [資料總管]

    資源選單中醒目提示 [數據總管] 選項的螢幕快照。

  5. 在 [資料總管] 頁面上,選取命令列中的 [新增容器] 選項。

    [數據總管] 命令行中 [新增容器] 選項的螢幕快照。

  6. 在 [新增容器] 對話方塊中,使用下列設定建立新的容器:

    設定
    資料庫識別碼 cosmicworks
    資料庫輸送量類型 手動
    資料庫輸送量數量 1000
    容器識別碼 products
    分割區索引鍵 /category/name

    [數據總管] 中 [新增容器] 對話框的螢幕快照,其中每個字段都有各種值。

    重要

    在本教學課程中,我們會先將資料庫調整為 1,000 RU/秒的共用輸送量,以最大化數據遷移的效能。 資料移轉完成後,我們會縮小為已佈建輸送量的 400 RU/s。

  7. 選取 [確定] 以建立資料庫和容器。

  8. 開啟終端機來執行命令,以在容器中填入資料。

    提示

    您可以在此選擇性地使用 Azure Cloud Shell。

  9. 從 NuGet 安裝 dotnet 工具的 cosmicworks v2

    dotnet tool install --global cosmicworks  --version 2.*
    
  10. 使用 cosmicworks 工具,使用您稍早在此實驗室中記錄的 [URI] 和 [主要金鑰]值,在 API for NoSQL 帳戶中填入範例產品資料。 這些記錄的值將分別用於 endpointkey 參數。

    cosmicworks \
        --number-of-products 1759 \
        --number-of-employees 0 \
        --disable-hierarchical-partition-keys \
        --connection-string <nosql-connection-string>
    
  11. 觀察命令列工具的輸出。 它應該將1759個專案新增至容器。 包含的範例輸出會為了簡潔而截斷。

    ── 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
    
  12. 返回您帳戶的 [資料總管] 頁面。

  13. 在 [資料] 區段中,展開 cosmicworks 資料庫節點,然後選取 [調整]

    資料庫節點內 [調整] 選項的螢幕快照。

  14. 將輸送量從 1,000 減少到 400

    資料庫輸送量設定縮減為 400 RU/秒的螢幕快照。

  15. 在命令列中,選取 [儲存]

    [資料總管] 命令行中 [儲存] 選項的螢幕快照。

  16. 在 [資料] 區段中,展開並選取 [產品] 容器節點。

    資料庫節點內展開容器節點的螢幕快照。

  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.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)
    
  22. 結果應該是較小的項目陣列,該陣列已篩選為只包含至少有一個標籤且 name 值為 Tag-32。 再度為了簡潔起見,此處包含輸出的子集。

    [
      ...
      {
        "name": "HL Touring Frame - Yellow, 60",
        "category": "Components",
        "subcategory": "Touring Frames",
        "tags": [
          "Components",
          "Touring Frames",
          "Yellow",
          "60"
        ]
      },
      ...
    ]
    

建立 ASP.NET Web 應用程式

現在,您將使用範例專案範本建立新的 ASP.NET Web 應用程式。 接著,您將探索原始程式碼並執行範例以熟悉應用程式,再使用適用於 .NET 的 Azure SDK 提供 Azure Cosmos DB 連線能力。

重要

本教學課程會以透明方式從 NuGet 提取套件。 您可以使用 dotnet nuget list source 來驗證套件來源。 如果您沒有 NuGet 做為套件來源,請使用 dotnet nuget add source 將網站安裝為來源。

  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 應用程式。 觀察執行中應用程式的全部三個頁面。

    使用佔位元數據執行之範例 Web 應用程式的螢幕快照。

  7. 藉由終止執行中程序來停止執行中的應用程式。

    提示

    使用 Ctrl+C命令停止執行中的程序。或者,您可以關閉並重新開啟終端機。

  8. 使用目前專案資料夾作為工作區,開啟 Visual Studio Code。

    提示

    您可以在終端機中執行 code .以開啟Visual Studio Code,並將工作目錄自動開啟為目前的工作區。

  9. 瀏覽至並開啟 Services/ICosmosService.cs 檔案。 觀察 RetrieveActiveProductsAsyncRetrieveAllProductsAsync 預設方法實作。 這些方法會建立第一次執行專案時要使用的產品靜態清單。 這裡提供其中一個方法的截斷範例。

    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),
            ...
        };
    }
    
  10. 瀏覽至並開啟 Services/ICosmosService.cs 檔案。 觀察 CosmosService 類別的目前實作。 這個類別會實作 ICosmosService 介面,但不會覆寫任何方法。 在此內容中,類別會使用預設介面實作,直到介面中提供實作的覆寫為止。

    public class CosmosService : ICosmosService
    { }
    
  11. 最後,流覽至並開啟 Models/Product.csModels/Category.cs 檔案。 觀察每個檔案中定義的記錄類型。 本教學課程中將會在查詢中使用這些類型。

    public record Product(
        string id,
        Category category,
        string sku,
        string name,
        string description,
        decimal price
    );
    
    public record Category(
        string name
    );
    

使用 .NET SDK 查詢資料

接下來,您會將適用於 .NET 的 Azure SDK 新增至此範例專案,並使用程式庫從 API for NoSQL 容器查詢資料。

  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. 建立 CosmosService 類別的新空白建構函式。

    public CosmosService()
    { }
    
  7. 在建構函式中,建立 CosmosClient 類別的新執行個體,以您先前在實驗室中記錄的 [主要連接字串] 值傳入字串參數。 將這個新執行個體儲存在 _client 成員中。

    public CosmosService()
    { 
        _client = new CosmosClient(
            connectionString: "<primary-connection-string>"
        );
    }
    
  8. 回到 CosmosService 類別,建立名為 container 且類型為 Container 的新 private 屬性。 設定 get 存取子以傳回 cosmicworks 資料庫和 products 容器。

    private Container container
    {
        get => _client.GetDatabase("cosmicworks").GetContainer("products");
    }
    
  9. 建立名為 RetrieveAllProductsAsync 的新非同步方法,以傳回 IEnumerable<Product>

    public async Task<IEnumerable<Product>> RetrieveAllProductsAsync()
    { }
    
  10. 針對後續步驟,在 RetrieveAllProductsAsync 方法中新增此程式碼。

    1. 使用 GetItemLinqQueryable<> 泛型方法來取得 IQueryable<> 類型的物件,您可將其用於建構語言整合式查詢 (LINQ)。 將該物件儲存在名為 queryable 的變數中。

      var queryable = container.GetItemLinqQueryable<Product>();
      
    2. 使用 WhereOrderByDescending 擴充方法建構 LINQ 查詢。 使用 ToFeedIterator 擴充方法來建立迭代器,以從 Azure Cosmos DB 取得資料,並將迭代器儲存在名為 feed 的變數中。 將此整個運算式包裝在 using 陳述式中,以便稍後處置迭代器。

      using FeedIterator<Product> feed = queryable
          .Where(p => p.price < 2000m)
          .OrderByDescending(p => p.price)
          .ToFeedIterator();
      
    3. 使用泛型 results 類型建立名為 List<> 的新變數。

      List<Product> results = new();
      
    4. 建立會逐一查看的 while 迴圈,直到 feed變數的 HasMoreResults 屬性傳回 false 為止。 此迴圈可確保您迴圈處理伺服器端結果的所有頁面。

      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. 傳回 results 清單作為 RetrieveAllProductsAsync 方法的輸出。

      return results;
      
  11. 建立名為 RetrieveActiveProductsAsync 的新非同步方法,以傳回 IEnumerable<Product>

    public async Task<IEnumerable<Product>> RetrieveActiveProductsAsync()
    { }
    
  12. 針對後續步驟,在 RetrieveActiveProductsAsync 方法中新增此程式碼。

    1. 使用 SQL 查詢建立名為 sql 的新字串,以擷取多個欄位,其中篩選條件 (@tagFilter) 套用至每個項目的 tags 陣列。

      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)
      """;
      
    2. 建立名為 query 的新 QueryDefinition 變數,並傳入 sql 字串作為唯一的查詢參數。 此外,使用 WithParameter 流體方法將 red 值套用至 @tagFilter 參數。

      var query = new QueryDefinition(
          query: sql
      )
          .WithParameter("@tagFilter", "red");
      
    3. 使用 GetItemQueryIterator<> 泛型方法和 query 變數來建立迭代器,以從 Azure Cosmos DB 取得資料。 將迭代器儲存在名為 feed 的變數中。 將此整個運算式包裝在 using 陳述式中,以便稍後處置迭代器。

      using FeedIterator<Product> feed = container.GetItemQueryIterator<Product>(
          queryDefinition: query
      );
      
    4. 使用 while 迴圈逐一查看多頁的結果,並將值儲存在名為 results的泛型 List<> 中。 傳回 results 作為 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 上的範例程式碼檢查原始程式碼。

驗證最終應用程式

最後,您將執行已啟用熱重新載入的應用程式。 執行應用程式會驗證您的程式碼是否可從 API for NoSQL 存取資料。

  1. 回到終端機,執行應用程式。

    dotnet run
    
  2. 執行命令的輸出應該包含應用程式執行所在的連接埠和 URL 清單。 開啟新的瀏覽器,然後瀏覽至執行中的 Web 應用程式。 觀察執行中應用程式的全部三個頁面。 每個頁面現在都應該包含來自 Azure Cosmos DB 的即時資料。

清除資源

如果不再需要本教學課程中使用的資料庫,請予以刪除。 若要這麼做,請瀏覽至帳戶頁面,選取 [資料總管]、選取 cosmicworks 資料庫,然後選取 [刪除]

下一步

既然您已使用 Azure Cosmos DB 建立第一個 .NET Web 應用程式,您現在可以深入了解 SDK 以匯入更多資料、執行複雜的查詢,以及管理 Azure Cosmos DB for NoSQL 資源。