ASP.NET MVC 中使用WebSocket 筆記
1.採用控制器的方法 這個只寫建立連結的方法的核心方法
1.1 踩坑 網上都是直接 傳個非同步方法 直接接受連結 自己嘗試了好多次連結是開啟的,到時獲取不到連結裡面的內容!! (如果是我理解有問題的話,歡迎討論,畢竟這個問題卡了我好久!)
1.2 自己建立連結的使用截圖 方法


1 /// <summary>
2 /// WebSocket連結 demo地址 ws://Localhost:8080/Get
3 /// </summary>
4 [HttpGet]
5 public void Get()
6 {
7 if (System.Web.HttpContext.Current.IsWebSocketRequest)
8 {
9 //System.Web.HttpContext.Current.AcceptWebSocketRequest(AnalysisOptionChat);
10 System.Web.HttpContext.Current.AcceptWebSocketRequest(async (context) => await AnalysisOptionChat(context));
11 }
12 }
1.3 判斷是WebSocket 連結後 處理訊息


1 /// <summary>
2 /// WebSocket連結操作
3 /// </summary>
4 /// <param name="context"></param>
5 /// <returns></returns>
6 private async Task AnalysisOptionChat(AspNetWebSocketContext context)
7 {
8 var webSocket = context.WebSocket;
9 #region 測試demo
10 try
11 {
12 ConsoleWrite.ConsoleInfo($"Websocket client add--> 自己需要實現 儲存連結");
13 WebSocketReceiveResult clientData = null;
14 do
15 {
16 var buffer = new ArraySegment<byte>(new byte[1024 * 1000]);
17 //if (clientData.MessageType == WebSocketMessageType.Text && !clientData.CloseStatus.HasValue)
18 if (webSocket.State == WebSocketState.Open && clientData.MessageType == WebSocketMessageType.Text)
19 {
20 string msgString = Encoding.UTF8.GetString(buffer.Array, 0, clientData.Count);
21 var sendData = string.Empty;
22 if ("rub".Equals(msgString))//心跳
23 {
24
25 }
26 else
27 {
28 int size = clientData.Count;
29
30 #region 通知
31 #endregion
32
33 #region DB持久化 操作
34 #endregion
35 }
36 }
37 }
38 //while (!clientData.CloseStatus.HasValue);
39 while (webSocket.State == WebSocketState.Open);
40
41 var state = webSocket.State;
42 ConsoleWrite.ConsoleWarning($"Websocket client closed1-->{state.ToString()}");
43 ConsoleWrite.ConsoleWarning($"Websocket client closed2-->{clientData.CloseStatus.Value}");
44 //關閉事件
45 await webSocket.CloseAsync(clientData.CloseStatus.Value, clientData.CloseStatusDescription, CancellationToken.None);
46 }
47 catch (Exception ex)
48 {
49 Console.WriteLine(ex.Message);
50 }
51
52 #endregion
53 }
1.4 在Asp.Net MVC 中使用可能會遇到 跨域的問題 一下是解決方案


1 <system.webServer>
2 <!--全域性跨域-->
3 <httpProtocol>
4 <customHeaders>
5 <add name="Access-Control-Allow-Origin" value="*" />
6 <!--<add name="Access-Control-Allow-Headers" value="*" />
7 <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />-->
8 </customHeaders>
9 </httpProtocol>
10 <system.webServer>
.NET Core 中使用WebSocket 筆記
1.在WepApi中使用法 這個只寫建立連結的方法的核心方法
1.首先需要在Startup.cs 裡面的 ConfigureServices裡面配置跨域 如果不牽扯跨域的話 可以忽略 1,2 (裡面的跨域) 跨域詳細配置如下


1 services.AddCors(options =>
2 {
3 options.AddPolicy("WebSocketCors", builder =>
4 {
5 builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
6 });
7 });
2.然後在 Configure方法 裡面加入管道


1 app.UseWebSockets(new Microsoft.AspNetCore.Builder.WebSocketOptions
2 {
3 //保持活動間隔
4 KeepAliveInterval = TimeSpan.FromMinutes(5),
5 });
6
7 // 注意這個是重點!!!!
8 app.UseMiddleware<WebsocketHandlerMiddleware>();
9
10 //自定義跨域規則
11 app.UseCors("WebSocketCors");
詳細截圖如下
3. 請求中介軟體 WebsocketHandlerMiddleware.cs 詳細介紹如下


1 public class WebsocketHandlerMiddleware
2 {
3 private readonly RequestDelegate _next;
4
5 public WebsocketHandlerMiddleware(RequestDelegate next)
6 {
7 _next = next;
8 }
9
10 public async Task Invoke(HttpContext context)
11 {
12 if (context.Request.Path == "/ws")
13 {
14 //客戶端與伺服器成功建立連線後,伺服器會迴圈非同步接收客戶端傳送的訊息,收到訊息後就會執行Handle(WebsocketClient websocketClient)中的do{}while;直到客戶端斷開連線
15 //不同的客戶端向伺服器傳送訊息後臺執行do{}while;時,websocketClient實參是不同的,它與客戶端一一對應
16 //同一個客戶端向伺服器多次傳送訊息後臺執行do{}while;時,websocketClient實參是相同的
17 if (context.WebSockets.IsWebSocketRequest)
18 {
19 var webSocket = await context.WebSockets.AcceptWebSocketAsync();
20
21 }
22 else
23 {
24 context.Response.StatusCode = 404;
25 }
26 }
27 else
28 {
29 await _next(context);
30 }
31 }
32 }
裡面處理 WebSocket 請求訊息的內容 和 1.3 中方法是一樣的 我這裡就不重複了 兩者的區別都只是 獲取方式不一樣而已。
.NET Core 中使用SignalR筆記
1.在WepApi中使用法 這個只寫建立連結的方法的核心方法 以及相關方法介紹
所使用的Nuget 包 如下:
1.1 首先需要在Startup.cs 裡面的 ConfigureServices方法 注入且配置跨域.


1 #region SignalR
2
3 services.AddCors(options =>
4 {
5 options.AddPolicy("SignalRCors", builder =>
6 {
7 builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
8 });
9 });
10
11 services.AddSignalR().AddHubOptions<SignalrHub>(options =>
12 {
13 options.EnableDetailedErrors = true;
14 })
15 // 支援MessagePack
16 .AddMessagePackProtocol();
17
18 #endregion
同時還需要 注入加入宣告週期 管控
//特殊的
services.AddSingleton<SignalrHub>();
1.2 在Configure方法裡面 的相關使用


1 //自定義跨域規則
2 app.UseCors("SignalRCors");
3
4 //需要在 Map裡面 指定路由
5 //app.UseHttpsRedirection();
6 app.UseEndpoints(endpoints =>
7 {
8 endpoints.MapControllers();
9 //可以設定SignalR相關引數,這裡設定地址
10 endpoints.MapHub<SignalrHub>("hubs/signalr", options =>
11 {
12 //配置 幾種方式
13 options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling;
14 });
15 });
1.3 SignalrHub.cs 集線器類的使用介紹 裡面有許多用不上的 自己按照需求自己過濾 主要就是 OnConnectedAsync() 建立連結 OnDisconnectedAsync()斷開連結 方法的使用!


1 //建立SingalR中心跨域
2 [EnableCors("SignalRCors")]
3 public class SignalrHub : Hub
4 {
5 //ReceiveMessage 為客戶端監聽的 方法名稱
6 private static string clientSendMethodName = "ReceiveMessage";
7
8 //Redis 儲存資訊Key
9 private static string signalrRedisKey = "SignalRConnections";
10
11 public SignalrHub()
12 {
13
14 }
15
16
17 #region Send
18
19 /// <summary>
20 /// 傳送訊息-指定使用者集合傳送訊息
21 /// </summary>
22 /// <param name="userIds">通知使用者集合</param>
23 /// <param name="sendObject">通知OBject</param>
24 /// <returns></returns>
25 public async Task SendUserMessage(List<int> userIds,object sendObject)
26 {
27 //從redis 獲取 userIds 對應的 ConnectionId 進行推送
28 var connectionUserList = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
29 if(connectionUserList.Count()<=0) throw new Exception("無連線使用者,無法進行訊息推送。");
30 var sentUserClient = connectionUserList.Where(x => userIds.Contains(x.UserId)).ToList();
31 var sendMeaaageToJson = JsonHelper.ObjectToJsonCamelCase(sendObject);
32
33 var connectionIds = sentUserClient.Select(y => y.ConnectionId);
34
35 //全部
36 //await Clients.All.SendAsync(clientSendMethodName, new { data = sendMeaaageToJson });
37
38 //指定
39 await Clients.Clients(connectionIds).SendAsync(clientSendMethodName, new { data = sendMeaaageToJson });
40 }
41
42
43 //傳送訊息--傳送給所有連線的客戶端
44 public async Task SendMessage(string msg)
45 {
46 //await Clients.All.SendAsync(clientSendMethodName, msg);
47 Console.WriteLine($"保持心跳連結-->接收引數:{msg}");
48 }
49
50
51
52 /// <summary>
53 /// 除 connectionId 之外的所有傳送message
54 /// </summary>
55 /// <param name="connectionId"></param>
56 /// <param name="message"></param>
57 /// <returns></returns>
58 public Task SendAllExceptMe(string connectionId, string message)
59 {
60
61 return Clients.AllExcept(connectionId).SendAsync(clientSendMethodName, $"{Context.ConnectionId}: {message}");
62 }
63
64 #endregion
65
66
67
68 #region Group分組的話 依據職位 或者 角色來業務迴圈獲取
69
70
71
72 #endregion
73
74
75 #region overrides
76
77 /// <summary>
78 /// 當新的客戶端連線建立時執行的操作
79 /// </summary>
80 /// <returns></returns>
81 public override async Task OnConnectedAsync()
82 {
83 //建立者使用者Id
84 var clientUserId = AuthHelper.GetUserId(Context.User);
85 //建立者使用者Name
86 var clientUserName = Context.User.Identity.Name;
87 //建立ConnectionId
88 var connectionId = Context.ConnectionId;
89
90 if (clientUserId <= 0 || string.IsNullOrWhiteSpace(clientUserName))
91 {
92 throw new Exception("建立連線異常,無法獲取使用者資訊。");
93 }
94
95 Console.WriteLine($"OnConnectedAsync建立連結----userId:{clientUserId},userName:{clientUserName},connectionId:{ Context.ConnectionId}");
96
97 var userConnections = new List<UserConnection>();
98 userConnections.Add(new UserConnection() { UserId = clientUserId, UserName = clientUserName, ConnectionId = connectionId, CreateTime = DateTime.Now });
99
100 //redis儲存連線使用者資訊
101 RedisService.SetLPushValue(signalrRedisKey, false, userConnections);
102
103 //獲取所有使用者的連結資訊
104 //var aaa = RedisService.GetLPushData<UserConnection>(signalrRedisKey,0,10000000);
105
106 await base.OnConnectedAsync();
107 }
108
109
110 /// <summary>
111 /// 當客戶端斷開連線時執行的操作
112 /// </summary>
113 /// <param name="exception"></param>
114 /// <returns></returns>
115 public override async Task OnDisconnectedAsync(Exception exception)
116 {
117 //建立者使用者Id
118 var clientUserId = AuthHelper.GetUserId(Context.User);
119 //建立者使用者Name
120 var clientUserName = Context.User.Identity.Name;
121 //建立ConnectionId
122 var connectionId = Context.ConnectionId;
123 //NLogHelper.ActionWarn();
124
125 Console.WriteLine($"OnDisconnectedAsync斷開連結----userId:{clientUserId},clientUserName:{clientUserName},connectionId:{ connectionId}");
126
127 var connectionUserList = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
128
129 //在redis裡面依據 Value 移除
130 var removeItem = connectionUserList.Where(x => x.ConnectionId == connectionId).FirstOrDefault();
131 if (removeItem != null)
132 {
133 var Drow = await RedisService.LRemAsync(signalrRedisKey, removeItem);
134 //var connectionUserLists = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
135 }
136 await base.OnDisconnectedAsync(exception);
137 }
138
139 protected override void Dispose(bool disposing)
140 {
141 base.Dispose(disposing);
142 }
143
144 #endregion
145
146
147 #region ClearOverTime 清除超時的垃圾資料
148
149 public async Task ClearOverTimeUserRedis(int houre=24)
150 {
151 var connectionUserList = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
152 var thisTime = DateTime.Now;
153 var delConnection = connectionUserList.Where(x=>(thisTime-x.CreateTime).Duration().TotalHours >= houre).ToList();
154 if (delConnection != null)
155 {
156 foreach (var delItem in delConnection)
157 {
158 var Drow = await RedisService.LRemAsync(signalrRedisKey, delItem);
159 //var connectionUserLists = RedisService.GetLPushData<UserConnection>(signalrRedisKey, 0, int.MaxValue);
160 }
161 }
162 }
163
164 #endregion
165 }
1.4 SignalrHub.cs 裡面所用到的使用者連結 UserConnection.cs 類


1 [Serializable]
2 public class UserConnection
3 {
4 /// <summary>
5 /// 使用者Id
6 /// </summary>
7 public int UserId { set; get; }
8
9 /// <summary>
10 /// 使用者名稱稱
11 /// </summary>
12 public string UserName { set; get; }
13
14 /// <summary>
15 /// 連線Id
16 /// </summary>
17 public string ConnectionId { set; get; }
18
19 /// <summary>
20 /// 建立時間
21 /// </summary>
22 public DateTime CreateTime { set; get; }
23 }
作者宣告:
1.文章轉載請註明出處 !!!
2.文章 如有不正確之處歡迎大家討論,交流, 如果感覺寫的還行,或者幫助了您,請點個贊哈,再次謝過~