分享程式代碼相關筆記
目前文章總數:157 篇
最後更新:2024年 12月 07日
1. SignalR Hub | : | 配置SignalR 可註冊的名稱與實際行為 |
2. 背景服務 | : | 實現推播,客戶端註冊後會從背景服務持續推播資料給客戶端 |
3. 初始化 | : | 使用SignalR的基本配置 |
4. 檢視器 | : | 用Razor實現前端註冊SignalR後接收資料的渲染 |
要架設SignalR伺服器首先要先進行Nuget安裝
這邊安裝7.0.0版本,伺服器端的版本建議與客戶端一致,否則容易發生異常
Microsoft.AspNetCore.SignalR.Common
建立一個UpdateHub.cs,可供註冊SendUpdate方法,並且會回傳Message。
內容如下:
using Microsoft.AspNetCore.SignalR;
namespace NetCoreSignalRWebSiteExample.SignalR
{
public class UpdateHub : Microsoft.AspNetCore.SignalR.Hub
{
//事件名稱SendUpdate 行為:回傳message
public async Task SendUpdate(string message)
{
await Clients.All.SendAsync("SendUpdate", message);
}
}
}
伺服器建立一個背景服務,會在每5秒自動將訊息推播給用戶,並且將Server上的count累加1
實現資訊變化,用戶能即時收到的效果
public class PageBackroundUpdaterService : BackgroundService
{
private readonly IHubContext<UpdateHub> _hubContext;
// 1. 配置變數,版本號、間隔時間
private int _versionNumber = 0;
private readonly int _second = 5 * 1000;//5秒
public PageBackroundUpdaterService(IHubContext<UpdateHub> hubContext
)
{
_hubContext = hubContext;
_versionNumber = 0;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// 2. 編寫返回資訊
var data = $@"回報時間:{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") } 版本號:{_versionNumber}";
// 3. 推播訊息給客戶端
await _hubContext.Clients.All.SendAsync("SendUpdate", data);
// 4. 輪詢時間
await Task.Delay(_second, stoppingToken);
_versionNumber++;
}
}
public override void Dispose()
{
base.Dispose();
}
}
打開Program.cs進行以下配置,讓SignalR可以生效,並且有對應的Url進行WebSocket連線
3. 配置 SignalR 路由 : “UpdateHub” 表示提供Hub註冊名稱
using NetCoreSignalRWebSiteExample.Background;
using NetCoreSignalRWebSiteExample.SignalR;
var builder = WebApplication.CreateBuilder(args);
\\配置其他Service...
// 1. 添加 SignalR
builder.Services.AddSignalR();
// 2. 增加背景服務 - 輪詢 Push SignalR
builder.Services.AddHostedService<PageBackroundUpdaterService>();
var app = builder.Build();
\\配置其他app configure...
app.UseEndpoints(endpoints =>
{
//3. 配置 SignalR 路由
endpoints.MapHub<UpdateHub>("UpdateHub");
});
app.Run();
於第三部分. 前端實現SignalR 章節的內容
先對專案按下滑鼠右鍵
選擇發佈
執行發佈
發布後的檔案搬移到資料夾下,範例放在D:\IIS_Server
選擇新增網站
黑框的部分自行配置,範例中Port為7531
完成後,啟動該網站
開啟命令提示字元
輸入以下:
ipconfig/all
可以得到本機的IP位置
打開瀏覽器,輸入以下,可以發現SignalR是正常的
http://192.168.42.177:7531/UpdateHub
頁面放著可以持續得到Server端回傳的資料
對應第一部分 => 1.專案架構 => 4. 檢視器
以下是完整代碼
@{
ViewData["Title"] = "SignalR連線測試頁面";
}
<!DOCTYPE html>
<html>
<head>
<!-- 1. ※此CDN 有可能失效,最好是加入至專案中 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/7.0.0/signalr.js"></script>
</head>
<body>
<!-- 2. 接收內容 -->
<div id="updateContainer"></div>
<script>
// 3. 預設頁面值
var updateContainer = document.getElementById("updateContainer");
updateContainer.innerHTML = `<p>New update: 初始化 </p>`;
// 4. 創建 SignalR 連接
const connection = new signalR.HubConnectionBuilder()
.withUrl("UpdateHub")
.build();
// 5. 監聽 SendUpdate 事件
connection.on("SendUpdate", (message) => {
const updateContainer = document.getElementById("updateContainer");
updateContainer.innerHTML += `<p>New update: ${message}</p>`;
});
// 6. 啟動
connection.start()
.then(() => {
console.log("連接 SignalR 成功");
})
.catch((error) => {
console.log("錯誤訊息:" + error);
});
</script>
</body>
</html>
伺服器端安裝的是SignalR 7.0.0 版本
因此客戶端需要使用對應的SignalR.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/7.0.0/signalr.js"></script>
如果為了測試方便,不將檔案引入前端框架,可以查詢CDN的位置,將對應.js引入前端代碼中
https://learn.microsoft.com/zh-tw/aspnet/core/signalr/javascript-client?view=aspnetcore-7.0&tabs=visual-studio
1. 依賴庫 | : | 引用SignalR客戶端套件 |
2. 權限項 | : | 配置網路使用權限、Http可明文使用(範例測試用) |
3. 主程式 | : | 顯示接收到SignalR伺服器端的資料 |
打開bundle.gradle
在dependencies最下方引用,版本建議與Server一致
implementation group: 'com.microsoft.signalr', name: 'signalr', version: '7.0.0'
打開Android.Manifest.xml
1. 添加連線到網路權限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
2. 在Android 9(API_28)以後,不允許Http(明文)的連線,為了方便測試我們要繞過Android的安全策略
android:networkSecurityConfig="@xml/network_security_config"
繞過Android的安全策略,還需要添加一個檔案 network_security_config.xml 以下位置
※根目錄 app 開始
G:\\AndroidGetSignalRExample\\app\\src\\main\\res\\xml
network_security_config.xml 內容如下:
IP是對應自己本機的位置,模擬器Debug模式下是連線本機IP (192.168.42.177),不可直接用localhost
※也可以從代理Proxy配置是另一Http測試解法
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.42.177</domain>
</domain-config>
</network-security-config>
依序完成下方六個步驟
package com.example.androidgetsignalrexample;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;
//SignalR 依賴庫
import com.microsoft.signalr.HubConnection;
import com.microsoft.signalr.HubConnectionBuilder;
import com.microsoft.signalr.HubConnectionState;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class MainActivity extends AppCompatActivity {
private HubConnection hubConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1. 檢查網路
if (isNetworkAvailable(this)) {
Log.d("MyApp", "有網路");
} else {
Log.d("MyApp", "無網路");
}
//2-1. 建立Signalr連接
try {
hubConnection = HubConnectionBuilder.create("http://192.168.42.177:7531/UpdateHub").build();
// 2-2. 註冊SignalR,等待被推播
hubConnection.on("SendUpdate", (message) -> {
try {
//2-3. 執行緒更新UI上物件
runOnUiThread(() -> {
TextView textView = findViewById(R.id.Information);
textView.setText("SignalR Server回傳訊息:" + message);
});
}
catch (Exception e)
{
Log.e("MyApp" , "錯誤訊息: "+e.getMessage());
}
}, String.class);
// 3. 啟動SignalR連線
if(hubConnection.getConnectionState() == HubConnectionState.DISCONNECTED)
{
Log.d("MyApp", "進行連接SignalR");
hubConnection.start().blockingAwait();
}
}
catch (Exception e)
{
Log.d("MyApp", e.getMessage());
}
}
private Handler handler = new Handler();
//檢查網路狀態
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
return false;
}
}
運行Android Studio 模擬器
模擬器成功收到SignalR伺服器傳來的資料
手機、Web的資訊是一致的,在同個時間下伺服器推播的資訊,大家都相同(時間、版本號一致)