后台
1 using Microsoft.AspNetCore.Authorization;
2
3 using Microsoft.AspNetCore.SignalR;
4
5 using PaddypestChart.DataAccess.Core.IService.IAPP;
6
7 using System;
8
9 using System.Collections.Generic;
10
11 using System.Security.Claims;
12
13 using System.Threading.Tasks;
14
15 using Utility.src.Redis;
16
17
18
19 namespace Microsoft.AspNetCore.Builder
20
21 {
22
23 /// <summary>
24
25 ///
26
27 /// </summary>
28
29 [Authorize]
30
31 public class ChatHub : Hub
32
33 {
34
35 /// <summary>
36
37 ///
38
39 /// </summary>
40
41 private readonly object balanceLock = new object();
42
43
44
45 /// <summary>
46
47 /// 是否系统启动后第一次连接
48
49 /// </summary>
50
51 private static bool FirstConnected = true;
52
53
54
55 /// <summary>
56
57 ///
58
59 /// </summary>
60
61 IOnline online;
62
63
64
65 /// <summary>
66
67 ///
68
69 /// </summary>
70
71 ICommonUser commonUser;
72
73
74
75 /// <summary>
76
77 /// 构造函数
78
79 /// </summary>
80
81 /// <param name="online">服务注入</param>
82
83 /// <param name="commonUser">服务注入</param>
84
85 public ChatHub(IOnline online, ICommonUser commonUser)
86
87 {
88
89 this.online = online;
90
91 this.commonUser = commonUser;
92
93 }
94
95
96
97 /// <summary>
98
99 /// 向指定用户推送消息
100
101 /// </summary>
102
103 /// <param name="user"></param>
104
105 /// <param name="message"></param>
106
107 /// <returns></returns>
108
109 public async Task SendMessage(string user, string message) => await Clients.User(user).SendAsync("ReceiveMessage", message);
110
111
112
113 /// <summary>
114
115 /// 连接触发
116
117 /// </summary>
118
119 /// <returns></returns>
120
121 public override Task OnConnectedAsync()
122
123 {
124
125 if (FirstConnected)
126
127 {
128
129 //加锁,防止其它线程多次触发
130
131 lock (balanceLock)
132
133 {
134
135 if (FirstConnected)
136
137 {
138
139 //在线状态全设置成离线(记录数据保存在MSSQL)
140
141 online.SetOfflineOfAll();
142
143 FirstConnected = false;
144
145 }
146
147 }
148
149 }
150
151 //设置在线状态,更改数据库中在线状态字段,1=在线,0=离线
152
153 SetOnlineStatus(Context.ConnectionId, 1);
154
155 //向管理员推送用户在线信息
156
157 SendMessageAdmin();
158
159 if(Context.UserIdentifier=="admin")
160
161 {
162
163 //从Redis中获取未推送消息(管理员离线未接收)
164
165 var listRange = RedisHelper.ListRange<string>(Context.UserIdentifier) as List<string>;
166
167 //遍历数据逐条推送
168
169 foreach (var item in listRange)
170
171 {
172
173 Clients.User("admin").SendAsync("UploadFilesMessage","", item);
174
175 }
176
177 }
178
179 return base.OnConnectedAsync();
180
181 }
182
183
184
185 /// <summary>
186
187 /// 连接断开触发
188
189 /// </summary>
190
191 /// <param name="exception"></param>
192
193 /// <returns></returns>
194
195 public override Task OnDisconnectedAsync(Exception exception)
196
197 {
198
199 SetOnlineStatus(Context.ConnectionId);
200
201 SendMessageAdmin(0);
202
203 return base.OnDisconnectedAsync(exception);
204
205 }
206
207
208
209 /// <summary>
210
211 /// 加入组
212
213 /// </summary>
214
215 /// <param name="groupName"></param>
216
217 /// <returns></returns>
218
219 public async Task AddToGroup(string groupName)
220
221 {
222
223 await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
224
225
226
227 await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has joined the group {groupName}.");
228
229 }
230
231
232
233 /// <summary>
234
235 /// 从组中删除
236
237 /// </summary>
238
239 /// <param name="groupName"></param>
240
241 /// <returns></returns>
242
243 public async Task RemoveFromGroup(string groupName)
244
245 {
246
247 await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
248
249
250
251 await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has left the group {groupName}.");
252
253 }
254
255
256
257 /// <summary>
258
259 /// 向管理员推送信息
260
261 /// </summary>
262
263 public async void SendMessageAdmin(int status = 1)
264
265 {
266
267 if (Context.UserIdentifier == "admin") return;
268
269 var name = Context.User.FindFirstValue(ClaimTypes.GivenName);
270
271 var statusstr = status == 1 ? "上线" : "下线";
272
273 await Clients.User("admin").SendAsync("DynamicMessage", status, $"用户 {name} {statusstr}啦!");
274
275 }
276
277
278
279 /// <summary>
280
281 /// 设置在线状态(保存至数据库)
282
283 /// </summary>
284
285 /// <param name="conneciionId"></param>
286
287 /// <param name="status"></param>
288
289 public void SetOnlineStatus(string conneciionId, int status = 0)
290
291 {
292
293 var appUser = commonUser.AppUserModebyLoginName(Context.UserIdentifier);
294
295 online.SetOnlineStatus(appUser, conneciionId, status);
296
297 }
298
299
300
301 /// <summary>
302
303 /// 客户端调用,表示信息已接收,数据从Redis中删除
304
305 /// </summary>
306
307 /// <param name="message"></param>
308
309 public void CallBlack(string message)
310
311 {
312
313 RedisHelper.ListRemove("admin",message);
314
315 }
316
317
318
319 }
320
321 }
前端
1 //需要引用
2
3 //提示框插件
4
5 <script src="~/lib/toastr-2.1.4/toastr.min.js"></script>
6
7 //signalr必须
8
9 <script src="~/lib/signalr/dist/browser/signalr.js"></script>
10
11
12
13 "use strict";
14
15 let connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
16
17
18
19 //记录重连次数
20
21 let number = 0;
22
23
24
25 (function () { initializeToastr(); connectionStar();})();
26
27
28
29 //初始化toastr插件属性
30
31 function initializeToastr() {
32
33 toastr.options = {
34
35 progressBar: true,
36
37 closeButton: false,
38
39 debug: false,
40
41 positionClass: "toast-bottom-right",
42
43 onclick: null,
44
45 showDuration: "300",
46
47 hideDuration: "1000",
48
49 timeOut: 5000,
50
51 extendedTimeOut: 5000,
52
53 showEasing: "swing",
54
55 hideEasing: "linear",
56
57 showMethod: "fadeIn",
58
59 hideMethod: "fadeOut"
60
61 };
62
63 }
64
65
66
67 function connectionStar() {
68
69 initializeToastr();
70
71 //开始连接
72
73 connection.start().then(function () {
74
75 if (number > 0) {
76
77 //弹出提示框
78
79 toastr.success("连接成功!");
80
81 //连接成功,重置重连次数
82
83 number = 0;
84
85 }
86
87 }).catch(function (err) {
88
89 toastr.error("连接断开,正在重新连接(" + number + ")......");
90
91
92
93 number++;
94
95 //同步方法,等待执行完成
96
97 setTimeout(() => connectionStar(), 5000);
98
99 });
100
101 }
102
103
104
105 //接收推送消息
106
107 //function内参数,取决于后台中[await Clients.User("").SendAsync(method,status,message)]参数个数
108
109 //参数顺序一一对应
110
111 connection.on("DynamicMessage", function (status, message) {
112
113 initializeToastr();
114
115 //status 1=在线,2=离线
116
117 if (status === 1)
118
119 toastr.info(message);
120
121 else
122
123 toastr.info("<dev style='color:#C7C7C7'>" + message + "</dev>");
124
125 //获取iframe对象
126
127 let iframe = document.getElementById("J_iframe").contentWindow;
128
129 //获取iframe打开的Url
130
131 let url = iframe.location.href;
132
133 //判断iframe打开的是否是OnlineUsers页面
134
135 if (url.indexOf("OnlineUsers") >= 0)
136
137 iframe.clientAjax();
138
139 });
140
141
142
143 //接收推送消息
144
145 connection.on("UploadFilesMessage", function (userId, message) {
146
147 toastr.options.closeButton = true;
148
149 toastr.options.timeOut = 20000;
150
151 toastr.info(message);
152
153
154
155 //想服务器推送消息,告知服务器消息已接收,"CallBlack"表示后台函数名
156
157 connection.invoke("CallBlack", message).catch(function (err) {
158
159 return toastr.error(err.toString());
160
161 });
162
163 });
164
165
166
167 //连接断开触发
168
169 connection.onclose(function () {
170
171 //重新连接
172
173 setTimeout(() => connectionStar(), 5000);
174
175 });
176
177
178
179 signalR主要方法
180
181 JS
182
183 let connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
184
185 //连接
186
187 connection.start().then(function () {
188
189 //连接成功操作
190
191 ......
192
193 }).catch(function (err) {
194
195 //连接失败操作
196
197 ......
198
199 });
200
201 //接收推送
202
203 connection.on("method", function (userId, message) {
204
205 ......
206
207 });
208
209 //发送消息
210
211 connection.invoke("method", message).catch(function (err) {
212
213 //发送失败操作
214
215 ......
216
217 });
218
219 //断开
220
221 connection.onclose(function () {
222
223 ......
224
225 });
后台调用
1 /// <summary>
2
3 /// 连接触发
4
5 /// </summary>
6
7 /// <returns></returns>
8
9 public override Task OnConnectedAsync()
10
11 {
12
13
14
15 }
16
17 /// <summary>
18
19 /// 连接断开触发
20
21 /// </summary>
22
23 /// <param name="exception"></param>
24
25 /// <returns></returns>
26
27 public override Task OnDisconnectedAsync(Exception exception)
28
29 {
30
31
32
33 }
34
35 //消息推送
36
37 await Clients.User("").SendAsync(method,status,message);
38
39
40
41 其它类调用需要使用到注入
42
43 public void Test([FromServices]IHubContext<ChatHub> hubContext)
44
45 {
46
47 hubContext.Clients.User(userId)
48
49 .SendAsync(method, arg1, arg2);
50
51 }