[ASP.NET MVC][SignalR][Vue3] 即時回報進度百分比教學 #CH2
SignalR 是 ASP.NET 實現網頁雙向溝通的一種方式,傳統的網頁是單向溝通,只能由客戶端主動發送訊息至伺服器端,而雙向溝通就可以由伺服器端主動發送訊息至客戶端,可以解決網頁即時同步的問題。
SignalR 應用的場景非常多,舉凡需要即時同步的需求都適合,例如遊戲、股價、聊天室、投票、拍賣、監控等等,如果學會此技能,將可在網頁上做出更豐富的變化。
此範例模擬場景是某一按鈕執行時間過長,使用者不知道何時結束,容易因為等待太久,懷疑是否當機,而直接關閉網頁離開。
如果可以即時告知使用者目前執行進度百分比的話,因為可預期何時結束,也知道系統正在執行沒有當機,讓使用者願意等待直到執行完畢。
範例環境是ASP.NET Core SignalR 搭配 Vue3 的使用方式,適合有使用 Vue3 前端的朋友使用。
Contents
建立專案
開啟 Visual Studio 在新增專案範本時選擇「ASP.NET Core Web 應用程式 (Model-View-Controller)」。
輸入專案名稱、路徑。
架構選擇「.NET 6.0」版本,按下「建立」就會建立此專案。
新增 SignalR 用戶端程式庫
SignalR 前端需要 JavaScript 的類別庫才能運作,而後端的 SignalR 已包含在 ASP.NET Core 共用架構中。
這裡要先下載最新版的 signalr.js 到我們的專案內。
在「方案總管」中,以滑鼠右鍵按一下專案,然後選取「加入 > 用戶端程式庫」。
針對提供者選取「unpkg」
針對「程式庫」輸入「@microsoft/signalr@latest」
選取「選擇特定檔案」,展開「dist/browser」資料夾,然後選取「signalr.js」和「signalr.min.js」。
將「目標位置」設定為「wwwroot/js/signalr/」
安裝之後,在你的專案目錄下就會找到這些檔案。
加入 Vue3 類別庫
我們直接在 Layout 頁面引用 Vue3,開啟 \Views\Shared\_Layout.cshtml,在下方的 Script 引用增加語法:
<script src="https://unpkg.com/vue@next"></script>
建立 SignalR Hub 類別
SignalR 的 Hub 類別可以處理網頁上用戶端與伺服器端之間的溝通橋樑。
在專案的目錄中新增目錄,名稱為「Hubs」。
然後在「Hubs」目錄下新增新類別,名稱為「ProgressHub」。
然後在 ProgressHub 類別貼上以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using Microsoft.AspNetCore.SignalR; namespace CoreMVC_SignalR_Progress.Hubs { public class ProgressHub : Hub { /// <summary> /// 連線事件 /// </summary> /// <returns></returns> public override async Task OnConnectedAsync() { // 回傳連線ID await Clients.Client(Context.ConnectionId).SendAsync("SetHubConnId", Context.ConnectionId); await base.OnConnectedAsync(); } } } |
方法 OnConnectedAsync()
是每一個用戶連線後,都會觸發的事件,每次連線會得到 Context.ConnectionId
,我們就把 Context.ConnectionId
回傳到前端。
設定 SignalR
開啟 Program.cs 檔案,這裡要啟用 SignalR 服務,然後註冊 Hub 路由。
在 Program.cs 的 var app = builder.Build();
語法之前,加入此語法:
//加入 SignalR
builder.Services.AddSignalR();
在 app.Run();
語法之前,加入此語法:
//加入 Hub
app.MapHub<ProgressHub>("/progressHub");
SignalR 用戶端程式碼
接著就要編寫前端的程式碼,我們範例就直接寫在首頁上教學。
開啟 \Views\Home\Index.cshtml 檔案,可以清除原有全部程式碼,然後貼上以下語法:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<h1>SignalR + Vue3 即時回報進度百分比教學</h1> <div id="app" class="container"> <button type="button" class="btn btn-primary" v-on:click="StartProgress()">開始執行</button> <hr /> 執行進度 {{progress}} % <div class="progress"> <div class="progress-bar" role="progressbar" v-bind:style="'width: ' + progress + '%'" v-bind:aria-valuenow="progress" aria-valuemin="0" aria-valuemax="100"></div> </div> 執行結果: {{message}} </div> @section scripts{ <script src="~/js/signalr/dist/browser/signalr.js"></script> <script> const app = Vue.createApp({ data() { return { progress:'0' , message: '' , hub:{ connection: {} , HubConnId: '' } } } , created() { var self = this; self.hub.connection = new signalR.HubConnectionBuilder().withUrl("/progressHub").build(); //與Server建立連線 self.hub.connection.start().then(function () { console.log("連線完成"); }).catch(function (err) { alert('連線錯誤: ' + err.toString()); }); // 連線ID self.hub.connection.on("SetHubConnId", function (id) { self.hub.HubConnId = id; }); // 更新進度 self.hub.connection.on("UpdProgress", function (percent) { self.progress = percent; }); } , methods: { // 開始執行 StartProgress() { var self = this; // 組合表單資料 var postData = {}; postData['HubConnId'] = self.hub.HubConnId; self.progress = '0'; self.message = ''; // 使用 jQuery Ajax 傳送至後端 $.ajax({ url: '@Url.Content("~/Home/StartProgress")', method: 'POST', dataType: 'json', data: { inModel: postData, __RequestVerificationToken: $('@Html.AntiForgeryToken()').val() }, success: function (datas) { if (datas.ErrMsg) { alert(datas.ErrMsg); return; } self.message = datas.ResultMsg; }, error: function (err) { alert(err.status + " " + err.statusText + '\n' + err.responseText); } }); } } }); const vm = app.mount('#app'); </script> } |
這裡簡單製作一個按鈕,執行後會呼叫後端的 Action,同時傳送由 Hub 得到的 ConnectionId
到後端,讓後端知道該更新前端那一位使用者。
Controller 程式碼
接著開啟 \Controllers\HomeController.cs,在 Controller 要使用 SingalR 要先在建構子載入 Hub。
修改 HomeController 增加剛剛新增的 ProgressHub 類別:
1 2 3 4 5 6 7 8 |
private readonly ILogger<HomeController> _logger; private readonly IHubContext<ProgressHub> progressHubContext; public HomeController(ILogger<HomeController> logger, IHubContext<ProgressHub> _hubContext) { _logger = logger; progressHubContext = _hubContext; } |
圖片紅框處是會額外增加的程式碼。
我們從 HomeController 取得的 IHubContext<ProgressHub>
物件是為了與使用者 SingalR 前端做互動,取得這物件後,就可以在 Action 執行過程發送 WebSocket 訊息至前端了。
接著在 HomeController 下面增加一個 Action,語法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/// <summary> /// 模擬會執行很久的範例 /// </summary> /// <param name="inModel"></param> /// <returns></returns> public IActionResult StartProgress(Dictionary<string, string> inModel) { Dictionary<string, string> outModel = new Dictionary<string, string>(); int progress = 0; //執行 10 秒 for (int i = 1; i <= 10; i++) { Thread.Sleep(1000);//暫停1秒 progress = i * 10; progressHubContext.Clients.Client(inModel["HubConnId"]).SendAsync("UpdProgress", progress); } outModel["ResultMsg"] = "執行完成"; return Json(outModel); } |
這裡模擬 10 秒的動作,每 10% 就通知前端目前進度,實際專案可以自行計算百分比,然後每 1% 就更新一次,讓用戶覺得系統還在跑。
測試專案
做到這裡就可以按 F5 測試一下專案,開始執行後,就會顯示目前進度。
完成後,進度條就會跑到 100%。
你也可以試試看,學會 SignalR 就可以讓網頁互動性更豐富,這是一個簡單基本的 SignalR 教學,分享給你。
範例下載
推薦課程
相關學習文章
- [ASP.NET Core SignalR] 即時對話聊天室教學 #CH1
- [ASP.NET Core MVC + Vue3] 統一欄位格式定義及驗證設計範例 – 後端驗證 #CH1
- [ASP.NET Core MVC + Vue3 + Dapper] 前後台網站公告範例 – 後台查詢頁面教學 #CH1
如果你在學習上有不懂的地方,需要諮詢服務,可以參考站長服務,我想辨法解決你的問題
如果文章內容有過時、不適用或錯誤的地方,幫我在下方留言通知我一下,謝謝