練習 - 在 Redis 中快取資料

已完成

在此練習中,您會為戶外用品零售商將快取新增至部分完成的雲端原生應用程式。 您會將 Redis 新增至 AppHost 專案,然後在 WebApp 專案中實作輸出快取,並在 Catalog.API 專案中實作分散式快取。

安裝先決條件

.NET Aspire 的必要條件如下:

  • .NET 8
  • Visual Studio 2022 預覽版
  • Docker Desktop
  • Visual Studio 中的 .NET Aspire 工作負載

如果已安裝這些套件,則可以直接開始使用 Redis 快取。

安裝 .NET 8

請遵循此 .NET 8 連結,然後為您的作業系統選取正確的安裝程式。 例如,如果您使用 Windows 11 和新式處理器,請選取適用於 Windows 的 x64 .NET 8 SDK。

下載完成之後,請執行安裝程式並遵循指示。 在終端視窗中,執行下列命令以確認安裝成功:

dotnet --version

您應該會看到您已安裝的 .NET SDK 版本號碼。 例如:

8.0.300-preview.24203.14

安裝 Visual Studio 2022 預覽版

請遵循此 Visual Studio 2022 預覽版連結,然後選取 [下載預覽版]。 下載完成之後,請執行安裝程式並遵循指示。

安裝 Docker Desktop

請遵循此 Docker Desktop 連結,然後為您的作業系統選取正確的安裝程式。 下載完成之後,請執行安裝程式並遵循指示。 為了獲得最佳效能和相容性,請使用 WSL 2 後端。

開啟 Docker 傳統型應用程式並接受服務合約。

安裝 Visual Studio 中的 .NET Aspire 工作負載

使用 .NET CLI 安裝 .NET Aspire 工作負載:

  1. 開啟終端機。

  2. 使用此指令更新 .NET 工作負載:

    dotnet workload update
    

    您應該會看到一則訊息,指出工作負載已成功更新。

    No workloads installed for this feature band. To update workloads installed with earlier SDK versions, include the --from-previous-sdk option.
    Updated advertising manifest microsoft.net.sdk.ios.
    Updated advertising manifest microsoft.net.workload.mono.toolchain.net6.
    Updated advertising manifest microsoft.net.sdk.android.
    Updated advertising manifest microsoft.net.workload.emscripten.net7.
    Updated advertising manifest microsoft.net.workload.emscripten.net6.
    Updated advertising manifest microsoft.net.sdk.macos.
    Updated advertising manifest microsoft.net.workload.emscripten.current.
    Updated advertising manifest microsoft.net.workload.mono.toolchain.current.
    Updated advertising manifest microsoft.net.sdk.maui.
    Updated advertising manifest microsoft.net.workload.mono.toolchain.net7.
    Updated advertising manifest microsoft.net.sdk.maccatalyst.
    Updated advertising manifest microsoft.net.sdk.tvos.
    Updated advertising manifest microsoft.net.sdk.aspire.
    No workloads installed for this feature band. To update workloads installed with earlier SDK versions, include the --from-previous-sdk option.
    
    Successfully updated workload(s): .
    
  3. 使用此指令安裝 .NET Aspire 工作負載:

    dotnet workload install aspire
    

    您應該會看到 Aspire 工作負載已安裝的訊息。

    Installing Aspire.Hosting.Sdk.Msi.x64 ...... Done
    Installing Aspire.ProjectTemplates.Msi.x64 ..... Done
    Installing Aspire.Hosting.Orchestration.win-x64.Msi.x64 ............. Done
    Installing Aspire.Hosting.Msi.x64 ..... Done
    Installing Aspire.Dashboard.Sdk.win-x64.Msi.x64 ....... Done
    
    Successfully installed workload(s) aspire.
    
  4. 使用此指令確認已安裝 .NET Aspire 工作負載:

    dotnet workload list
    

    您應該會看到 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.
    

複製並修改範例應用程式

我們將使用 git 取得以 .NET Aspire 建置的範例應用程式。 該應用程式尚未設定快取:

  1. 在命令列中,瀏覽至您選擇的資料夾,您可以在其中使用程式碼。

  2. 執行下列命令以複製北山 eShop 範例應用程式:

    git clone -b aspire-cache https://github.com/MicrosoftDocs/mslearn-aspire-starter
    
  3. 開啟 Visual Studio,然後選取 [開啟專案或解決方案]

  4. 瀏覽至您複製 eShop 的資料夾,開啟 start 資料夾並選取 eShop.rediscache.sln 檔案,然後選取 [開啟]

  5. 在 [方案總管] 中,瀏覽至 WebApp/Components/Pages,然後按兩下 Catalog.razor

  6. 找出下列程式碼行:

    <SectionContent SectionName="page-header-subtitle">Start the season with the latest in clothing and equipment.</SectionContent>
    
  7. 使用下列程式碼取代該行:

    <SectionContent SectionName="page-header-subtitle">Start the season with the latest in clothing and equipment. It's @DateTime.Now</SectionContent>
    
  8. 若要啟動應用程式,請按 F5,或選取 [偵錯]>[開始偵錯]

  9. 如果 [啟動 Docker 桌面] 對話方塊出現,請選取 [是]

  10. eShop .NET Aspire 儀表板出現時,針對 webapp 資源選取其中一個端點:

    此螢幕擷取畫面顯示在 .NET Aspire 儀表板中啟動 webapp 的位置。

  11. 端點會顯示 Northern Mountains 首頁。 包括伺服器上的時間:

    顯示 Northern Mountains 首頁的螢幕擷取畫面,其中顯示伺服器端時間。

  12. F5 以重新整理頁面。 由於不會快取頁面,因此每當您重新整理頁面時,只要秒數有變化,顯示的時間就會變更。

  13. 變更為顯示 .NET Aspire 儀表板的瀏覽器索引標籤,然後在左側導覽中選取 [追蹤]

  14. 名為 webapp:GET / 的追蹤是對首頁的要求。 記下這些要求的一般持續時間,然後針對其中一個要求,選取 [詳細資料] 資料行中的 [檢視]

    .NET Aspire 儀表板的螢幕擷取畫面,其中顯示對 Northern Mountains 首頁之要求的追蹤 (沒有快取)。

  15. 在時間表檢視中,您會看到 webapp 呼叫了多個微服務以建構回應。

  16. 關閉 Northern Mountains 首頁和 .NET Aspire 儀表板。

  17. 在 Visual Studio 中,若要停止偵錯,請按 SHIFT - F5,或選取 [偵錯] > [停止偵錯]

新增快取支援服務

您已了解首頁如何在沒有快取的情況下執行,接下來我們將新增輸出快取,看看是否可改善回應性。 首先,將輸出快取元件新增至 AppHost 專案:

  1. 在 Visual Studio 的 [方案總管] 中,以滑鼠右鍵按一下 [eShop.AppHost] 專案並選取 [新增],然後選取 [.NET Aspire 套件]

  2. 在搜尋文字方塊中,於現有文字的結尾輸入 Redis

  3. 選取 [Aspire.Hosting.Redis] 套件。

  4. 在 [版本] 清單中,選取最新的 8.0.0 版本,然後選取 [安裝]

  5. 如果出現 [預覽變更] 對話方塊,請選取 [套用]

  6. 在 [接受授權] 對話方塊中,選取 [我接受]

  7. 在 [方案總管] 中展開 AppHost 專案,然後按兩下 Program.cs

  8. 找出以下幾行程式碼:

    // Databases
    
    var postgres = builder.AddPostgres("postgres").WithPgAdmin();
    var catalogDb = postgres.AddDatabase("CatalogDB");
    
  9. 緊接在這幾行後面,新增下列程式碼:

    // Cache
    var redis = builder.AddRedis("cache");
    
  10. 找出以下這一行程式碼,它會將目錄 API 專案新增至 .NET Aspire 協調流程:

    var catalogApi = builder.AddProject<Catalog_API>("catalog-api")
        .WithReference(catalogDb);
    
  11. 若要將 Redis 快取傳遞至目錄 API 專案,請將該程式碼取代為以下幾行:

    var catalogApi = builder.AddProject<Catalog_API>("catalog-api")
        .WithReference(catalogDb)
        .WithReference(redis);
    

    注意

    我們將使用目錄 API 中的快取來執行分散式快取。

  12. 找出以下這一行程式碼,它會將 WebApp 專案新增至 .NET Aspire 協調流程:

    builder.AddProject<WebApp>("webapp")
        .WithReference(catalogApi);
    
  13. 若要將 Redis 快取傳遞至 WebApp 專案,請將該程式碼取代為以下幾行:

    builder.AddProject<WebApp>("webapp")
        .WithReference(catalogApi)
        .WithReference(redis);
    

    注意

    我們將使用 WebApp 中的快取來執行輸出快取。

  14. 若要儲存 Program.cs 檔案,請按 CTRL - S,或選取 [檔案] > [儲存 Program.cs]

在 WebApp 專案中使用輸出快取

現在,我們將使用 WebApp 專案中的 Redis 快取來快取首頁輸出:

  1. 在 Visual Studio 的 [方案總管] 中,以滑鼠右鍵按一下 WebApp 專案、選取 [新增],然後選取 [.NET Aspire 套件]

  2. 在搜尋文字方塊中,於現有文字的結尾輸入 Redis

  3. 選取 Aspire.StackExchange.Redis.OutputCaching 套件。

  4. 在 [版本] 清單中,選取最新的 8.0.0 版本,然後選取 [安裝]

  5. 如果出現 [預覽變更] 對話方塊,請選取 [套用]

  6. 在 [接受授權] 對話方塊中,選取 [我接受]

  7. 安裝完成後,在 [方案總管] 中展開 WebApp,然後按兩下 Program.cs

  8. 找出下列程式碼行:

    var builder = WebApplication.CreateBuilder(args);
    
  9. 緊接在該行後面,若要將輸出快取新增至專案,請新增下列程式碼:

    builder.AddRedisOutputCache("cache");
    
  10. 找出下列程式碼行:

    var app = builder.Build();
    
  11. 緊接在該行後面,若要將快取中介軟體新增至要求管線,請新增下列程式碼:

    app.UseOutputCache();
    
  12. 在 [方案總管] 中,展開 [WebApp] > [元件] > [頁面],然後按兩下 Catalog.razor

  13. 找出下列程式碼行:

    @attribute [StreamRendering]
    
  14. 緊接在該行後面,若要快取首頁,請新增下列程式碼:

    @attribute [Microsoft.AspNetCore.OutputCaching.OutputCache(Duration = 10)]
    

測試輸出快取

輸出快取現已在 Northern Mountains 首頁中實作。 我們來測試一下:

  1. 在 Visual Studio 中,若要啟動應用程式,請按 F5,或選取 [偵錯] > [開始偵錯]

  2. eShop .NET Aspire 儀表板出現時,針對 webapp 資源選取其中一個端點:

    此螢幕擷取畫面顯示在 .NET Aspire 儀表板中啟動 webapp 的位置。

  3. 端點會顯示 Northern Mountains 首頁,包括伺服器上的時間。

  4. F5 以重新整理頁面。 由於頁面會快取 10 秒,所以只有在快取要求超過 10 秒後,顯示的時間才會變更。

  5. 變更為顯示 .NET Aspire 儀表板的瀏覽器索引標籤,然後在左側導覽中選取 [追蹤]

  6. 名為 webapp:GET / 的追蹤是對首頁的要求。 對首頁的某些要求無法從快取因應,其時間點與您先前記下的持續時間相似。 不過,其他要求是從快取傳回的,其持續時間明顯較短。

  7. 針對其中一個較短的要求,選取 [詳細資料] 資料行中的 [檢視]。 請注意,要求是從 Redis 快取中擷取的:

    .NET Aspire 儀表板的螢幕擷取畫面,其中顯示快取要求的追蹤。

  8. 關閉 Northern Mountains 首頁和 .NET Aspire 儀表板。

  9. 在 Visual Studio 中,若要停止偵錯,請按 SHIFT - F5,或選取 [偵錯] > [停止偵錯]

使用分散式快取

我們也可以使用 Redis 在 Catalog.API 專案中執行分散式快取:

  1. 在 Visual Studio 的 [方案總管] 中,以滑鼠右鍵按一下 [Catalog.API] 專案、選取 [新增],然後選取 [.NET Aspire 套件]

  2. 在搜尋文字方塊中,於現有文字的結尾輸入 Redis

  3. 選取 Aspire.StackExchange.Redis.DistributedCaching 套件。

  4. 在 [版本] 清單中,選取最新的 8.0.0 版本,然後選取 [安裝]

  5. 如果出現 [預覽變更] 對話方塊,請選取 [套用]

  6. 在 [接受授權] 對話方塊中,選取 [我接受]

  7. 安裝完成後,在 [方案總管] 中展開 Catalog.API,然後按兩下 Program.cs

  8. 找出下列程式碼行:

    var builder = WebApplication.CreateBuilder(args);
    
  9. 緊接在該行後面,若要將輸出快取新增至專案,請新增下列程式碼:

    builder.AddRedisDistributedCache("cache");
    
  10. 在 [方案總管] 中展開 Catalog.API > API,然後按兩下 CatalogApi.cs

  11. 找出下列程式碼,它會宣告 GetAllItems 方法:

    public static async Task<Results<Ok<PaginatedItems<CatalogItem>>, BadRequest<string>>> GetAllItems(
        [AsParameters] PaginationRequest paginationRequest,
        [AsParameters] CatalogServices services)
    {
    
  12. 若要透過相依性插入取得 Redis 快取,請修改該程式碼以將新的參數新增至方法:

    public static async Task<Results<Ok<PaginatedItems<CatalogItem>>, BadRequest<string>>> GetAllItems(
        [AsParameters] PaginationRequest paginationRequest,
        [AsParameters] CatalogServices services,
        IDistributedCache cache)
    {
    
  13. 移除 GetAllItems 方法的完整內容,並將其取代為下列程式碼:

    var pageSize = paginationRequest.PageSize;
    var pageIndex = paginationRequest.PageIndex;
    
    var totalItems = await services.DbContext.CatalogItems
        .LongCountAsync();
    
    // Check that there are cached items
    var cachedItems = await cache.GetAsync("catalogItems");
    
    if (cachedItems is null)
    {
        // There are no items in the cache. Get them from the database
        var itemsOnPage = await services.DbContext.CatalogItems
            .OrderBy(c => c.Name)
            .Skip(pageSize * pageIndex)
            .Take(pageSize)
            .AsNoTracking()
            .ToListAsync();
    
        // Store the items in the cache for 10 seconds
        await cache.SetAsync("catalogItems", Encoding.UTF8.GetBytes(System.Text.Json.JsonSerializer.Serialize(itemsOnPage)), new()
        {
            AbsoluteExpiration = DateTime.Now.AddSeconds(10)
        });
    
        ChangeUriPlaceholder(services.Options.Value, itemsOnPage);
        return TypedResults.Ok(new PaginatedItems<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage));
    
    }
    else
    {
        // There are items in the cache. Deserialize them to display.
        var itemsOnPage = System.Text.Json.JsonSerializer.Deserialize<List<CatalogItem>>(cachedItems);
        // Make sure itemsOnPage is not null
        if (itemsOnPage is null)
        {
            itemsOnPage = new List<CatalogItem>();
        }
    
        ChangeUriPlaceholder(services.Options.Value, itemsOnPage);
        return TypedResults.Ok(new PaginatedItems<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage));
    }
    

測試分散式快取

分散式快取現已在 Catalog.API 專案中實作。 我們來測試一下:

  1. 在 Visual Studio 中,若要啟動應用程式,請按 F5,或選取 [偵錯] > [開始偵錯]

  2. eShop .NET Aspire 儀表板出現時,針對 catalog-api 資源選取端點:

    此螢幕擷取畫面顯示在 .NET Aspire 儀表板中啟動目錄 API 的位置。

  3. 端點會顯示目錄 API 微服務的 Swagger 介面。 在 /api/v1/catalog/items 方法旁,選取 [GET]

  4. 選取 [立即試用],然後選取 [執行]。 結果會顯示在 [回應本文] 視窗中:

    此螢幕擷取畫面顯示在 Swagger 使用者介面中顯示的目錄結果。

  5. 按一下 [執行] 數次,再次呼叫 API。 這些要求只要晚於第一個要求不到 10 秒,就應該可從快取中取得項目。

  6. 變更為顯示 .NET Aspire 儀表板的瀏覽器索引標籤,然後在左側導覽中選取 [追蹤]

  7. 名為 catalog-api:GET /api/v1/catalog/items 的追蹤是目錄 API 之 items 方法的要求。 請注意,該方法的第一個要求需要較長的時間來制定後續要求,供 API 從 Redis 快取中取得項目:

    .NET Aspire 儀表板追蹤頁面的螢幕擷取畫面,其中包含對目錄 API 的快取要求。

  8. 關閉 Swagger 頁面和 .NET Aspire 儀表板。

  9. 在 Visual Studio 中,若要停止偵錯,請按 SHIFT - F5,或選取 [偵錯] > [停止偵錯]