分享程式代碼相關筆記
目前文章總數:157 篇
最後更新:2024年 12月 07日
上篇上篇 完成 SLB + Session Sticky 配置,最後遺留下 2台Web機器的 SignalR 無法互通問題。
此問題MSDN提出第3個建議解法,常態性解決 Server 實際部署受到環境影響的問題
※假設使用 SignalR Server 註冊到另一台 SignalR Server 會無法通過 SLB + Session Sticky 配置。
因為 SLB 會動態分配到 Server,有可能自己連到自己造成 Crash
我們目標是啟用 Azure Signalr Service Backplane 模式,管理所有連接的 SignalR Server,當需要推播時,由 Azure Signalr Service Server 完成推播給所有用戶的方法
SignalR Scaleout with Azure Service Bus 適合早期的代碼,現在新版 .net Core 已經建議使用 Azure SignalR Service
在 Web 應用程式中建置即時通訊,快速又輕鬆
有了 Azure SignalR Service,您就不需要兼任即時通訊大師!
因為在 Web 應用程式中新增即時通訊就和佈建服務一樣簡單!
簡單說,使用 Asp.net Core 如果使用 SignalR + Azure ,此服務已經整合大部分需要解決的問題,包含(只列幾項,詳細清參考連結):
1. 跨平台 |
2. 自動負載平衡 |
3. 各種程式語言支持 |
4. 最佳化傳輸方式 |
5. 高可用 |
基本上,如果小型開發或者測試,可以用免費版的,20000次訊息的推播
如果是大型產品使用 SLA 是考量的重要指標
N/A | : | 服務商想停機就停機 |
99.9 % | : | 服務商一年停機時間不超過 9 小時 |
99.95 % | : | 服務商一年停機時間不超過 5 小時 |
可以參照官方的說明進行,但代碼與設定還需要自行摸索,本篇已完善補齊一些實做細節
官方建構文件
進入 Azure 儀錶板後 -> 選擇左側 Menu -> 建立資源
1. 輸入 SignalR |
2. 點擊 Azure SignalR Service |
點擊 Create 開始進行設定
1. 地區依照自己的所在位置,會影響時區 |
2. 選擇變更 |
選擇變更後 -> 選擇 Free_F1 方案 (依照自己所需)
1. 補完所有資訊 |
2. 檢閱 + 建立 |
最後檢查沒問題就選擇建立
※如果誤選擇付費方案,建立後,就立刻計費了
等待一下,就會出現建立完成訊息
1. Web資源檔 | : | 將 SignalR 8.0.0.js 下載,讓 .cshtml 引用,使前端網站可以註冊 SignalR 服務 |
2. 初始化配置 | : | 依賴注入 Azure SignalR Service 等配置 |
3. 配置 | : | 每個 Server 為了辨識,增加自己的代號、使用的 Port 號、Azure SignalR Service 連線位置 |
4. SignalR Hub | : | Web 伺服器實現 SignalR ,並且提供前端 Publish 與後端 Subscribe |
5. 前端頁面 | : | 提供聊天室註冊 SignalR 並且可發送訊息,與接收訊息功能 |
Asp.net Core 的專案,需要安裝 Microsoft.Azure.SignalR 套件
可從微軟給定的CDN SignalR 8.0.0 的位置下載,並放進自己的專案中,可在不對外,並且只能在內部網路的狀況下使用 SignalR
SignalR 8.0.0 下載
在 Program.cs 初始化配置中,將 Azure 連線設定
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// 1. 添加 Azure Signalr Service 設定
var azureConnection = builder.Configuration["Azure:SignalR:ConnectionString"];
builder.Services.AddSignalR().AddAzureSignalR(options =>
{
// 2. 這邊要參考 Azure 上的連線字串
options.ConnectionString = azureConnection;
});
var app = builder.Build();
...... 略
app.UseEndpoints(endpoints =>
{
//3. 配置 SignalR 路由
endpoints.MapHub<UpdateHub>("UpdateHub");
});
...... 略
app.Run();
Azure 連線設定,應從儀表表中取得設定連結
※範例代碼會移除此連結,要自行取得自己的
appsettings.json 增加 SiteNumber、ConnectionStrings 完成辨識 Server 與 Azure SingnalR Service 連線字串的工作
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"SiteNumber": "2",
"Site": "WebStie Port: XXXX",
"AllowedHosts": "*",
"Azure": {
"SignalR": {
"ConnectionString": "你的Azure SignalR Service 的連線字串"
}
}
}
依序將 1. ~ 4. 項 SignalR 的推播
※可以將 4. 步驟替換自己真實資料的保存
public class UpdateHub : Microsoft.AspNetCore.SignalR.Hub
{
private readonly IConfiguration _configure;
private static string _Site = string.Empty;
private int _siteNumber = 0;
public UpdateHub()
{
_configure = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
_Site = _configure.GetValue("Site", string.Empty);
//1. 求出自己站點編號的 2 ^ (SiteNumber-1) 值 EX: 編號1=1 / 編號2=2 / 編號3=4
_siteNumber = (int)Math.Pow(2, (_configure.GetValue("SiteNumber", 1) - 1));
}
/// <summary>
/// 2. 建立連接時,將歷史訊息回傳
/// </summary>
/// <returns></returns>
public override async Task OnConnectedAsync()
{
var getData = FakeHistoryMessage();
foreach (var message in getData)
{
await Clients.Caller.SendAsync("ReceiveMessage", message);
}
await base.OnConnectedAsync();
}
//事件名稱SendUpdate 行為:回傳message
public async Task SendUpdate(string message)
{
await Clients.All.SendAsync("SendUpdate", message);
}
/// <summary>
/// 3. 接收前端傳送訊息
/// </summary>
public async Task SendMessage(string user, string message)
{
var dateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var combineMessage = $@"[站點{_siteNumber} {dateTime}] {user}: {message}";
await Clients.All.SendAsync("ReceiveMessage", combineMessage);
}
/// <summary>
/// 4. 偽造歷史資料 ※實務資料源可為 Redis / Mysql / SqlServer / MongoDB .....
/// </summary>
private List<string> FakeHistoryMessage()
{
return new List<string>()
{
"[站點1 2024-4-29 05:32:35] Louis: 1",
"[站點2 2024-4-29 05:32:35] MilkTeaGreen: 2",
"[站點1 2024-4-29 05:33:17] Louis: 3",
"[站點2 2024-4-29 05:33:52] MilkTeaGreen: 4",
"[站點1 2024-4-29 05:34:12] Louis: 5",
"[站點2 2024-4-29 05:34:17] MilkTeaGreen: 6",
};
}
}
前端實現基本的 SignalR 連線工作,在 “ReciveMessage” 訂閱工作中
<script>
// 3. 預設頁面值
var updateContainer = document.getElementById("updateContainer");
updateContainer.innerHTML = `<p>New update: 初始化 </p>`;
// 4. 創建 SignalR 連接
const connection = new signalR.HubConnectionBuilder()
.withUrl("UpdateHub", { accessTokenFactory: () => "I am jwtToken" })
.build();
// 5. 監聽 SendUpdate 事件
connection.on("SendUpdate", (message) => {
const updateContainer = document.getElementById("updateContainer");
updateContainer.innerHTML += `<p>${message.message}</p>`;
});
// 6. 訂閱可接收訊息
connection.on("ReceiveMessage", function (message) {
const updateContainer = document.getElementById("updateContainer");
updateContainer.innerHTML += `<p>${message}</p>`;
});
// 7. 啟動
connection.start()
.then(() => {
console.log("連接 SignalR 成功");
})
.catch((error) => {
console.log("錯誤訊息:" + error);
});
// 8. 發送訊息到Hub 伺服器上
function sendMessage() {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
console.error("Error invoking SendMessage: " + err.toString());
});
}
</script>
將範例代碼部署到2個 Web 資料夾中
Web1的 appsetting.json 如下
Web2的 appsetting.json 如下
對 Web1 輸入指令
dotnet SingalRWebsiteUseAzureSignalRServiceBackPlateExample.dll --urls=http://localhost:6001
對 Web2 輸入指令
dotnet SingalRWebsiteUseAzureSignalRServiceBackPlateExample.dll --urls=http://localhost:6002
啟動 Nginx
※這邊的配置是基於上一篇 SLB + Session Sticky
進入配置好的首頁,並且開啟兩個分頁(第1個分頁連 web1 ; 第2個分頁連 web2)
輸入一些簡單文字,可以發現完成 SLB + Session Sticky 下的 SignalR 聊天室互動
未來要部署多個機器時,只要改一下 appsetting.json 的代號,即可部署完成
檢查 Azure 儀錶板可以發現:服務也有產生資料流