ASP.NET Blazor 怎麼處理狀態?(二)- 保存預設範本的 Count 值

前言

上一次的文章【ASP.NET Blazor 怎麼處裡狀態?】中,筆者說明了幾種在 Blazor 上保存狀態的常見用法,但是當時筆者無法在 [YourProjectName].Client 的專案裡安裝『Microsoft.AspNetCore.Http』、『Microsoft.AspNetCore.Http.Abstractions』、『Microsoft.AspNetCore.Http.Feature』這三個套件 均無法安裝成功,後來我發現,無法成功是正常的,這因為 [YourProjectName].Client 是執行在 browser 的沙箱(Sand box)裡面,試想,這三個套件都是相依於在沙箱裡,而這個沙箱內又以 Mono Runtime 來執行 .NET Standard,如果 .NET Standard 本身不支援那個 API 也無法執行對吧?更何況又在 browser 的沙箱環境中。這更不用說 Microsoft.AspNetCore.Http.Abstractions 裡還參照了在 Mono Runtime 裡不支援的 advapi32.dll & kernal32.dll 等

就算技術上可行,安全性其實也不允許你在沙箱內部存取外部 OS 資源。

也就是說,上次的那個作法是錯誤的,我們根本就不應該在 [YourProjectName].Client 裡面安裝那三個套件,應該回頭過來思考,我今天的需求是,要從 browser 將 COUNT 內容傳遞到 Server 上,並保存下來!也就是說,我們應該將 [YourProjectName].Client 這樣的專案當作是一個執行在前端browser 中包含 Front-End Framework 的 SPA 應用程式,這麼一來,是不是就清楚多了?因為 Client 是執行在 Browser 中,若不是 Blazor ,傳統 SPA 作法也是透過 JavaScript 執行 Ajax 的 Call Back 呼叫,將 Count 傳遞至 Web Server 上保存下來對吧?所以,Blazor 也會是相同的做法。


專案結構


正確做法是什麼?

(1). WebBlazorStateTest1.Client 的 Counter.cshtml

在 Counter.cshtml 裡,透過 view inject 注入 HttpClient 來撰寫呼叫 Web API 傳遞 currentCount 到後端並保存下來,由於程式碼非常簡單就不多做說明了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@page "/counter"
@inject HttpClient _httpClient;
 
<h1>Counter</h1>
 
<p>Current count: @currentCount</p>
 
<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>
 
@functions {
    int currentCount = 0;
 
    async void IncrementCount()
    {
        currentCount++;
 
        await _httpClient.PostAsync($"api/SampleData/SetCountState/?count={currentCount}", null);
    }
 
    async Task<HttpResponseMessage> GetCountState()
    {
        HttpResponseMessage message = await _httpClient.GetAsync("api/SampleData/GetCountState");
 
        return message;
    }
 
    protected async override void OnInit()
    {
        string test = await _httpClient.GetStringAsync("api/SampleData/GetCountState");
 
        currentCount = Convert.ToInt32(test);
 
        base.OnInit();
 
        this.StateHasChanged();
    }
}


(2). 啟用 MemoryCache

1
2
3
4
5
6
public void ConfigureServices(IServiceCollection services)
{
    //..略
 
    services.AddDistributedMemoryCache();
}


(3). 在 WebBlazorStateTest1.Server 的 SampleDataController 裡增加兩個 API 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected IMemoryCache _memoryCache;
protected IHttpContextAccessor _httpContextAccessor;
 
public SampleDataController(IMemoryCache memoryCache)
{
    _memoryCache = memoryCache;
}
 
/// <summary>
/// 從 MemoryCache 中,取得 Counter 數值
/// </summary>
/// <returns></returns>
[HttpGet("[action]")]
public int GetCountState()
{
    int result = 0;
    var counter = _memoryCache.Get<int?>("_COUNTER");
     
    if (counter.HasValue)
    {
        result = counter.Value;
    }
     
    return result;
}
[HttpPost("[action]")]
public int SetCountState(int count)
{
    return _memoryCache.Set<int>("_COUNTER", count);
}


接著,我們可以在 Counter 頁面得到保存 Count 數的效果如下圖:


但是,這時,如果開另外一個 browser 的話,別的使用者也會看見這個 Count 數,也就是說,它就像個 static 變數一樣,等於是共想於所有使用者,這似乎不是我們想要的,如果我們要每個人可以保存、並有自己的 Count 數值該怎麼做呢?

其實,最簡單的方式,就是用 Session,或者,在 Cache 的 Key 加上 By 登入的 User 的 userId 唯一值,像是 (”_user_id_xxxx”+”_COUNT”)使不同使用者不會重複即可,並將 Session 的 Provider 導向 Redis,以便適用 (Scale-Out/Load Balance )環境中,達到 狀態共享/高效能。


ASP.NET Blazor 系列文章導讀

(一)、ASP.NET Blazor 關鍵報告

(二)、Blazor 怎麼處裡狀態?

(三)、Blazor 怎麼處裡狀態?【保存預設範本的 Count 值】

(四)、Blazor 的 CRUD 應用程式 – Use Entity Framework Core

(五)、Blazor 如何使用自定義的 ApiHostBase?【接續 Clean Architecture 的 API 框架設計 (1)】

(六)、Blazor 如何使用自定義的 ApiHostBase?【接續 Clean Architecture 的 API 框架設計 (2)】

(七)、… 還在想 XDD




關於 Gelis:

資深 .NET 技術顧問

FB 社團 (軟體開發之路):

https://www.facebook.com/groups/361804473860062/

FB 粉絲團 (Gelis 的程式設計訓練營):

https://www.facebook.com/gelis.dev.learning/

我講授過的課程 SlideShare:

https://www.slideshare.net/GelisWu


以下是我經營的項目與內容:

(1). 企業內訓課程

(2). 專業顧問


企業內訓課程:

1. .NET Core 3.1 從入門到進階

先前實體課程連結

2. 跨平台的 Web API Framework 框架設計

先前實體課程連結

3. 決戰 OOAD 系列課程 - 使用 UML

先前實體課程連結

4. 單元測試 UnitTest 與 Moq 物件實務課程

先前實體課程連結

5. 快速開發系列 - C# Project Templates 範本設計

留言

  1. 期待這系列可以寫完!

    回覆刪除
    回覆
    1. Dear Not

      我會盡力抽空完成 XD 因為最近專案與顧問案兩頭燒 XDDD

      刪除

張貼留言

這個網誌中的熱門文章

什麼是 gRPC(二)- 來撰寫第一個 Hello World 吧!

什麼是 gRPC ?

開啟Hyper-V的內部虛擬網路