第四節:SignalR靈魂所在Hub模型及再探聊天室樣例

来源:https://www.cnblogs.com/yaopengfei/archive/2018/07/14/9304308.html
-Advertisement-
Play Games

一. 整體介紹 本節:開始介紹SignalR另外一種通訊模型Hub(中心模型),它是一種RPC模式,允許客戶端和伺服器端各自自定義方法並且相互調用,對開發者來說相當友好。 該節包括的內容有: ①:從零搭建 ②:Hub模型和URL匹配,預設模式和指定路徑 ③:伺服器端代碼介紹 ④:客戶端的兩種模式,代 ...


一. 整體介紹

  本節:開始介紹SignalR另外一種通訊模型Hub(中心模型),它是一種RPC模式,允許客戶端和伺服器端各自自定義方法並且相互調用,對開發者來說相當友好。   該節包括的內容有:     ①:從零搭建     ②:Hub模型和URL匹配,預設模式和指定路徑     ③:伺服器端代碼介紹     ④:客戶端的兩種模式,代理和非代理,各自的寫法     ⑤:伺服器端和客戶端包含的方法和各自如何自定義方法並且相互調用     ⑥:第三方調用的問題,比如:如何在控制器中調用客戶端的方法。     ⑦:再探聊天室樣例  

 

二. 從零搭建

 1. 新建MVC5項目,通過Nuget安裝程式集:Microsoft.AspNet.SignalR,安裝成功後如下圖。

2. 新建一個中心模型Hub類(MySpecHub1),該類繼承了Hub類,並且幾個必要方法可以override

 

3. 新建一個OWIN Startup Class(Startup),併在Configuration方法中指定使用的通訊模型的URl,  這裡採用預設的方式:如: app.MapSignalR(); 【後續展開介紹如何指定URL及其中的問題】

  PS: 程式啟動時候首先會找到該類,然後運行裡面的Configuration方法,從而url和通訊模型的匹配將生效。

 

4. 引入必要的JS文件,進行前端代碼的編寫,如下圖。【後續詳細介紹】

 

三. 模型和URL匹配

   我們都知道,在OWIN Startup Class(即Startup類)中Configuration方法中進行模型URL的指定,並且在很多例子中,看到都是這麼寫:app.MapSignalR(); 貌似並沒有配置URL,但事實上並不是這樣的,我們通過反編譯代碼可以看到,它會預設指定一個路徑  "/signalr"  ,如下圖:

  特別註意:這裡的"/signalr",與js端的自動生成代理類的代碼:<script src="~/signalr/hubs"></script>沒有任何毛線關係,這兩個根本不是一個東西!!!!!,只是路徑相似而已罷了。

   那麼如何指定路徑:

  通過 代碼:app.MapSignalR("/myhub1", new HubConfiguration()); 可以將路徑指定為:"/myhub1",至於前端頁面怎麼與之匹配,在下麵介紹。

  PS:這裡還可以配置其它參數,如下圖:

 

 

四. 伺服器端代碼介紹

   前端頁面的JS代碼有兩種模式,代理模式和非代理模式(下麵介紹),但無論JS使用哪種模式,伺服器端的代碼都是唯一不變。

1. MySpecHub1類繼承成Hub類,所以可以Override三個方法:

  (1). OnConnected:連接成功時調用

  (2). OnDisconnected:連接斷開時調用

  (3). OnReconnected:重連時調用

2. 自定義方法

  伺服器端可以自定義方法供客戶端調用,比如:  public void AddUser(string userName, string userId){....}

    特別特別註意:前端【代理模式】的情況下調用的伺服器端方法或者與代理文件建立連接時,有一個非常坑爹的規則,首字母必須小寫,比如伺服器端定義方法為:“AddUserMsg”,前端【代理模式】情況下調用必須寫成:“addUserMsg”;再比如這裡的Hub類為 "MySpecHub1",前端調用的時候必須寫成"mySpecHub1";對此我表示很無語,當年這一點坑了我很久!!!

  PS:上述指定是【代理模式】,【非代理模式】不存在這個問題。

雖然我們已經知道這個規則了,但經常寫著寫著就忘了,那麼如何解決上面這個問題呢?:

  這裡有兩個特性分別是:[HubName()] 和  [HubMethodName()],可以自行指定Hub類和自定義方法的名稱,指定為什麼,前端調用就用什麼,這樣【代理模式】下,坑爹的首字母小寫規則,就不存在了。為了後續不麻煩,所以我通常在每個方法上面都加: [HubMethodName(nameof(方法名))],這樣就不會存在問題了,如下圖:

  

 3. 上下文對象(this.Context)

  (1). 當前用戶的標記: this.Context.ConnectionId (Guid生成,不會重覆)

  (2). 其它信息:RequestCookies、Headers、QueryString、User、Request

4. 如何調用客戶端方法 

  使用Clients對象進行調用,Clients對象下的屬性和方法有:

    ① 向所有人發送(包括自己):All { get; }

    ② 向所有人發送(排除一些人):AllExcept(params string[] excludeConnectionIds);

    ③ 向指定人發送,一對一:Client(string connectionId);

    ④ 向一些人發送,一對多:Clients(IList<string> connectionIds);

    ⑤ 向某個組發送(排除一些人):Group(string groupName, params string[] excludeConnectionIds);

    ⑥ 向多個組發送(排除一些人):Groups(IList<string> groupNames, params string[] excludeConnectionIds);

    ⑦ 由Id標識的特定用戶:Users(IList<string> userIds);

    ⑧ 由Id標識的特定多用戶:User(string userId);

  調用形式比如:Clients.All.客戶端方法名稱

5. 組的概念(Groups對象)

  ① 將連接添加到指定組:Task Add(string connectionId, string groupName);

  ② 從指定組中刪除連接:Task Remove(string connectionId, string groupName);

  調用如:this.Groups.Add("", "");

截圖幾段代碼:

 

五. 客戶端(js)代碼介紹-代理模式

 1. 必備JS文件的引入

  前端Html頁面使用SignalR,必須引入兩個文件:JQuery和SignalR,必須JQuery在上,且最低版本為1.6.4,不能再低了。如下圖:

2. 代理JS代碼的生成

   代理JS代碼用戶幫助客戶端調用伺服器端自定義方法,註意這裡的引入路徑只能是: <script src="/signalr/js"></script> 或者  <script src="/signalr/hubs"></script>,至於為什麼路徑非要這麼寫?這個地方不糾結了,我們姑且就這麼使用(有興趣探討一下內部原理吧)。

  引入該代碼後,進入頁面F12,會發現多了JS代碼,沒錯,這就是自動生成的代理代碼,在前端代碼的編寫中,需要依賴該文件。

  可能會用人問,我把自動生成的這個JS代碼拷貝出來,單獨放到一個JS文件里,然後在頁面引入,並去掉生成代理代碼的這句話 <script src="/signalr/js"></script>,行不行呢?

  答案是:肯定行。

    但這種拷貝出來的方式有點Low,伺服器端代碼只要一改,我就需要重新拷貝一遍,那麼有沒有別的方便的方法呢?

    顯然有,大約有兩種方法。

  ①:藉助Microsoft.AspNet.SignalR.Utils程式集和指令。

  ②:藉助Microsoft.AspNet.SignalR.Utils程式集和VS開發工具的

  在這一節里,暫時不介紹這兩種方式,後面章節詳細介紹。

3. 如何與伺服器Hub模型路徑相配?

  在上面的代碼中介紹過,伺服器Hub模型預設的URL為"/signalr",那麼客戶端的代碼怎麼寫呢?

1   //1. 與伺服器路徑進行匹配
2   var conn = $.connection.hub;
3   //2. 與生成的代理類建立連接
4   var proxy = $.connection.mySpecHub1;

  乍一看,絲毫沒有看到與"/signalR"相關的代碼,不要急,這時去看一下自動生成代理類中的代碼,如下圖:

  

  我們再看一下SignalR的JS代碼中關於hubConnection方法的聲明,如下圖:

 

 

   配合第二個截圖簡單分析一下這塊源代碼,首先if判斷" 一真或為真",只要!url 和 useDefaultPath有一個是真的就進入方法體內部,然後在拼接 url+“/signalr”,如果不進入if方法體,那麼你輸入的url是什麼,這裡用的就是什麼。

  前面的代碼為: signalR.hub = $.hubConnection("/signalr", { useDefaultPath: false }); ||兩邊都為false,進入不了if方法體內部,所以URL就是預設輸入的“/signalr”。

4. 坑爹的調用規範

  在代理模式中,客戶端調用伺服器端方法或者與代理建立連接的時候,比如:

  ①:伺服器端的Hub名稱為MySpecHub1,客戶端調用的時候必須為首字母小寫:$.connection.mySpecHub1;

  ②:伺服器端自定義的方法為SendSingleMsg,客戶端調用的時候必須為首字母小寫:proxy.server.sendSingleMsg;

  註:非代理模式中則不存在這個問題!!!!

  解決: 引入兩個特性[HubName("")] 和 [HubMethodName("")]  ,放在伺服器端代碼上面,就解決了。 (詳見伺服器端代碼)

5. 客戶端方法的聲明和調用伺服器端方法

  ①. 聲明客戶端方法: proxy.client.xxx = function (x1, x2) {}       xxx代表客戶端方法名稱

  ②. 調用伺服器端方法: proxy.server.xxx(x1,x2);                          xxx代表伺服器端方法名稱

 註:這裡的proxy,是 $.connection.mySpecHub1; 與自動生成的代理類建立連接。

6. 伺服器端指定模型URL後,前端如何匹配?

  如伺服器端代碼為:app.MapSignalR("/myhub1", new HubConfiguration());

  ①. 當使用自動生成代理類js文件時候,與<script src="/signalr/hubs"></script>衝突,暫時未解決 (歡迎下方留言討論)

  ②. 手動引入代理類時候可以使用,只需添加 conn.url = "/myhub1"; 即可以將路徑改為 "/myhub1"。 

代碼如下:

通過Fiddler檢測一下。

 

7. 其它方法

  同PersistentConnection模式中相同,比如開啟和檢測斷線。

 

 

六. 客戶端(js)代碼介紹-非代理模式 

   有了前面代理模式的鋪墊,非代理模式就很容易了,下麵介紹一下在使用上的一些區別:

1. 基本使用

  不需要需要引入 <script src="/signalr/js"></script> 或者 <script src="/signalr/hubs"></script>,也不需要引入手動添加的代理類 <script src="~/Scripts/AutoProxy.js"></script>,但在代碼上要這麼寫,比如創建代理類: $.hubConnection().reateHubProxy("MySpecHub1");

詳細代碼如下:

1  //1. 與伺服器路徑進行匹配
2 var conn = $.hubConnection();
3 //2. 手動創建代理類
4  var proxy = conn.createHubProxy("MySpecHub1");

2. 在非代理模式中,伺服器端的Hub名稱和伺服器端自定義的方法不必首字母小寫(PS:小寫也能用)

  ①:伺服器端的Hub名稱為MySpecHub1,客戶端調用的時候 conn.createHubProxy("MySpecHub1");

  ②:伺服器端自定義的方法為SendSingleMsg,客戶端調用的時候必須為首字母小寫: proxy.invoke("SendSingleMsg", $("#j_receiveId").val(), $("#j_content").val());

  註:伺服器端的兩個特性[HubName("")] 和 [HubMethodName("")]仍然好用!!!

3. 聲明客戶端方法和調用伺服器端方法

  ①. 聲明客戶端方法: proxy.on("方法名",function(x1,x2,x3){});

  ②. 調用伺服器端方法: proxy.invoke("方法名", "參數1","參數2","參數3");

4 預設路徑匹配

  在不使用代理的情況下,$.hubConnection()與伺服器路徑進行匹配的時候,通過Fiddler可以發現,預設是"/signalr"路徑

5. 伺服器端指定路徑模型路徑:

  如伺服器端代碼為:app.MapSignalR("/myhub1", new HubConfiguration());

  客戶端對應的代碼為:$.hubConnection("/myhub1", { useDefaultPath: false });

  註:通過Fidder或者調試源代碼,可以看到路徑已經改為"/myhub1";

  特別補充:如果客戶端代碼var conn = $.hubConnection("/myhub1")這麼寫,useDefaultPath這個屬性預設為true,則最後的路徑為:"/myhub1/signalr",原因藉助前面的分析很容易理解了。

 

 

七. 第三方調用 

  上面介紹的所有代碼都是直接基於 Hub模型這個類來通信的,但在很多情況下,我們可能建立連接後,在別的頁面進行通信,而這個頁面沒法直接和Hub類相連接,我需要藉助控制器里的Action來通信,那麼問題來了,如何通過調用控制器里的方法來實現發送信息的功能呢?

  其實非常簡單,我們只需要通過 GlobalHost.ConnectionManager.GetHubContext<MySpecHub1>(); 獲取到這個Hub即可。

  代碼如下:

 1        /// <summary>
 2         /// 向所有人發送消息
 3         /// </summary>
 4         /// <param name="msg">發送的信息</param>
 5         public string MySendAll(string msg)
 6         {
 7             string myConnectionId = Session["connectionId"].ToString();
 8             //Hub模式
 9             var hub = GlobalHost.ConnectionManager.GetHubContext<MySpecHub1>();
10             hub.Clients.AllExcept(myConnectionId).receiveMsg($"用戶【{myConnectionId}】發來消息:{msg}");
11             return "ok";
12         } 

 

八. 聊天室樣例

   在本系列的第一節,基於WebSocket寫了一個聊天室樣例,還吐槽了一番,寫法很麻煩,這裡基於Signalr的Hub模型,再寫一次聊天室,並補充幾個新功能。

  效果圖如下:

  包括的功能有:

  ①:連接成功後通知所有人包括自己登錄成功。

  ②:離線後,通知除了自己以外的所有人已經離開。

  ③:通過輸入接收人的SessionId,實現一對一發送信息。

  ④: 通過點擊群發按鈕,向除了自己以外的所有人發送信息。

  ⑤:可以進入room1或room2房間,然後實現向指定房間內的所有人發送信息。

  ⑥:跳轉到新頁面,然後在新頁面實現向指定人發送消息。

下麵分享代碼,包括(Hub模型代碼,控制器代碼,前端代碼(代理和非代理兩套))

Hub模型代碼

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Threading.Tasks;
  5 using System.Web;
  6 using Microsoft.AspNet.SignalR;
  7 using Microsoft.AspNet.SignalR.Hubs;
  8 
  9 namespace HubDemo
 10 {
 11 
 12     //[HubName("MySpecHub1")]
 13     public class MySpecHub1 : Hub
 14     {
 15 
 16         /**************************************下麵是Override的方法*************************************************/
 17 
 18 
 19         #region 01-連接成功的時候調用
 20         /// <summary>
 21         /// 連接成功的時候調用
 22         /// </summary>
 23         /// <returns></returns>
 24         public override Task OnConnected()
 25         {
 26 
 27             //調用客戶端的方法
 28             Clients.All.LoginSuccessNotice($"用戶【{this.Context.ConnectionId}】登錄成功", this.Context.ConnectionId);
 29             return base.OnConnected();
 30         }
 31         #endregion
 32 
 33         #region 02-連接斷開的時候調用
 34         /// <summary>
 35         /// 連接斷開的時候調用
 36         /// </summary>
 37         /// <param name="stopCalled"></param>
 38         /// <returns></returns>
 39         public override Task OnDisconnected(bool stopCalled)
 40         {
 41             //除去自己以外的消息
 42             Clients.AllExcept(this.Context.ConnectionId).receiveMsg($"用戶【{this.Context.ConnectionId}】已經離開");
 43             return base.OnDisconnected(stopCalled);
 44         }
 45         #endregion
 46 
 47         #region 03-重新連接的時候調用
 48         /// <summary>
 49         /// 重新連接的時候調用
 50         /// </summary>
 51         /// <returns></returns>
 52         public override Task OnReconnected()
 53         {
 54             return base.OnReconnected();
 55         }
 56         #endregion
 57 
 58         /**************************************下麵是自定義的伺服器端方法*************************************************/
 59 
 60         #region 01-點對點發送消息
 61         /// <summary>
 62         /// 點對點發送消息
 63         /// </summary>
 64         /// <param name="receiveId"></param>
 65         /// <param name="msg"></param>
 66         public void SendSingleMsg(string receiveId, string msg)
 67         {
 68             Clients.Client(receiveId).receiveMsg($"用戶【{this.Context.ConnectionId}】發來消息:{msg}");
 69         }
 70         #endregion
 71 
 72         #region 02-群發消息
 73         /// <summary>
 74         /// 群發消息
 75         /// </summary>
 76         /// <param name="msg"></param>
 77         [HubMethodName(nameof(SendAllMsg))]
 78         public void SendAllMsg(string msg)
 79         {
 80             //除去自己以外的消息(不需要自己存儲ConnectionId)
 81             Clients.AllExcept(this.Context.ConnectionId).receiveMsg($"用戶【{this.Context.ConnectionId}】發來消息:{msg}");
 82         }
 83         #endregion
 84 
 85         #region 03-進入指定組
 86         /// <summary>
 87         /// 進入指定組
 88         /// </summary>
 89         /// <param name="roomName">組的名稱</param>
 90         [HubMethodName(nameof(EnterRoom))]
 91         public void EnterRoom(string roomName)
 92         {
 93             //進入組
 94             Groups.Add(this.Context.ConnectionId, roomName);
 95             //告訴自己進入成功
 96             Clients.Client(this.Context.ConnectionId).receiveMsg($"用戶【{this.Context.ConnectionId}】成功進入組:【{roomName}】");
 97         }
 98         #endregion
 99 
100         #region 04-向指定組發送消息
101         /// <summary>
102         /// 向指定組發送消息
103         /// </summary>
104         /// <param name="roomName">組名</param>
105         /// <param name="msg">內容</param>
106         [HubMethodName(nameof(SendRoomNameMsg))]
107         public void SendRoomNameMsg(string roomName, string msg)
108         {
109             //向指定組發送消息,如果這個組包含自己,將自己除外
110             Clients.Group(roomName, this.Context.ConnectionId).receiveMsg($"用戶【{this.Context.ConnectionId}】發來消息:{msg}");
111         }
112         #endregion
113 
114     }
115 }
View Code

控制器代碼

 1 using Microsoft.AspNet.SignalR;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace HubDemo.Controllers
 9 {
10     /// <summary>
11     /// Hub模型(中心模型)
12     /// 
13     /// </summary>
14     public class HubController : Controller
15     {
16         #region 01-代理模式頁面
17         /// <summary>
18         /// 代理模式頁面
19         /// </summary>
20         /// <returns></returns>
21         public ActionResult Index()
22         {
23             return View();
24         }
25         #endregion
26 
27         #region 02-非代理模式頁面
28         /// <summary>
29         /// 非代理模式頁面
30         /// </summary>
31         /// <returns></returns>
32         public ActionResult NoProxyIndex()
33         {
34             return View();
35         }
36         #endregion
37 
38         #region 03-第三方頁面
39         /// <summary>
40         /// 第三方頁面
41         /// </summary>
42         /// <param name="connectionId">當前用戶的連接標記</param>
43         /// <returns></returns>
44         public ActionResult OtherIndex(string connectionId)
45         {
46             Session["connectionId"] = connectionId;
47             return View();
48         }
49         #endregion
50 
51 
52         /****************************************************下麵是第三方調用方法****************************************************************/
53 
54 
55         #region 01-向所有人發送消息
56         /// <summary>
57         /// 向所有人發送消息
58         /// </summary>
59         /// <param name="msg">發送的信息</param>
60         public string MySendAll(string msg)
61         {
62             string myConnectionId = Session["connectionId"].ToString();
63             //Hub模式
64             var hub = GlobalHost.ConnectionManager.GetHubContext<MySpecHub1>();
65             hub.Clients.AllExcept(myConnectionId).receiveMsg($"用戶【{myConnectionId}】發來消息:{msg}");
66             return "ok";
67         } 
68         #endregion
69 
70 
71 
72     }
73 }
View Code

代理

  1 @{
  2     Layout = null;
  3 }
  4 
  5 <!DOCTYPE html>
  6 
  7 <html>
  8 <head>
  9 
 10     <meta name="viewport" content="width=device-width" />
 11     <title>Index</title>
 12     <script src="~/Scripts/jquery-3.3.1.min.js"></script>
 13     <script src="~/Scripts/jquery.signalR-2.3.0.js"></script>
 14     <!--自動生成代理類 -->
 15     <script src="/signalr/hubs"></script>
 16     <!--手動引入代理類 -->
 17     @*<script src="~/Scripts/AutoProxy.js"></script>*@
 18     <script type="text/javascript">
 19         $(function () {
 20 
 21             //一. 初始化信息
 22             //預設路徑
 23             //1. 與伺服器路徑進行匹配
 24             var conn = $.connection.hub;
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 斐波那契數列的5種python寫法       斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家 列昂納多·斐波那契 (Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”, ...
  • 任務佈置:製作簡單地鐵站點管理系統 要求一:正確配置系統,建立基本正常的數據通道;要求二:實現地鐵站點的登記,擁有查詢功能; 正文: 今天介紹labview虛擬儀器軟體中 labSQL 本地調用 Access資料庫 使用的方法,首先瞭解整體設計的 思維導圖 。 在思維導圖中資料庫是由 Access ...
  • 找出中文錯別字 1.5 代碼獲取 你可以通過下麵命令將代碼下載到實驗樓環境中,作為參照對比進行學習。 $ wget http://labfile.oss.aliyuncs.com/courses/828/Document.tar 可以預想到,假設我們的語料庫長度為 n ,我們可以以 O(1) 的時間 ...
  • 本文手把手教你,做出第一個Spring Cloud程式,Eureka的簡單入門使用 1、創建Spring Starter Project工程 點擊next,添加項目名 2、引入Spring Cloud 的 Eureka 點擊next 點擊 finish 3、配置項目的 application.pro ...
  • 考慮一下利用Python製作一個整蠱、木馬軟體,我提供思路。(清楚到沒學過編程的人也理解) 1、首先一個黑客做一個整蠱或者木馬軟體,一定不會讓你能夠關閉它。 2、裡面經常會附帶欺騙的方法。 3、最終實現某種目的。 前段時間在抖音上看到個有趣的程式,看樣子是VB寫的,首先就要用到欺騙的方法,利用軟體名 ...
  • 以下羅列了使用關係型資料庫中常見關係定義模板代碼 一對多 示例場景: 用戶與其發佈的帖子(用戶表與帖子表) 角色與所屬於該角色的用戶(角色表與多用戶表) 示例代碼 class Role(db.Model): """角色表""" __tablename__ = 'roles' id = db.Colu ...
  • 1、com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: 原因如下: 在預設設置下,Eureka服務註冊中心也會將自己作為客戶端來嘗試註冊它自己,所以我們需要禁用它的客戶端註冊行為。 禁止方式如下:在 ...
  • 參考鏈接:An Informal Introduction to Python 廢話:最近開始閱讀python3.7文檔,希望把容易混淆的知識記下來。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...