.net core 使用SignalR实现实时通信

Posted zhangjd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.net core 使用SignalR实现实时通信相关的知识,希望对你有一定的参考价值。

这几天在研究SignalR,网上大部分的例子都是聊天室,我的需求是把服务端的信息发送给前端展示。并且需要实现单个用户推送。

用户登录我用的是ClaimsIdentity,这里就不多解释,如果不是很了解,可以看这篇文章https://www.cnblogs.com/zhangjd/p/11332558.html

推荐https://www.cnblogs.com/laozhang-is-phi/p/netcore-vue-signalr.html#tbCommentBody这个博客,写的很详细,并且附有Dome

一、后端实现

1、引用SignalR包

Install-Package Microsoft.AspNetCore.SignalR

2、声明一个类来记录用户的连接信息。

1     public class SignalRModel
2     
3         public static Dictionary<string, SignalRStatus> StaticList = new Dictionary<string, SignalRStatus>();
4         public static Dictionary<string, string> SignalRList  get; set;  = new Dictionary<string, string>();
5     

3、声明Hub,这里我重写了连接和断开方法,用来绑定用户和连接的ConnectionId。(这个比较复杂,是因为我程序中执行的第三方程序,需要实时输出当前执行的程序的日志。但是调用的执行不可能直接写在控制器里,这样调用我没办法获取当前用户的登录Id。然后我就在发起连接和断开连接的方法处理了。)

 1 public class ChatHub : Hub
 2     
 3         /// <summary>
 4         /// 连接成功
 5         /// </summary>
 6         /// <returns></returns>
 7         public override Task OnConnectedAsync()
 8         
 9             var id = this.Context.ConnectionId;
10             var claimNameIdentifier = this.Context.User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.NameIdentifier)?.Value;
11             SignalRModel.SignalRList.Add(id, claimNameIdentifier);
12             if (SignalRModel.StaticList.Any(s => s.Key.Equals(claimNameIdentifier)))
13             
14                 SignalRModel.StaticList.Remove(claimNameIdentifier);
15             
16             SignalRModel.StaticList.Add(claimNameIdentifier, SignalRStatus.Open);
17             return base.OnConnectedAsync();
18         
19         /// <summary>
20         /// 断开连接
21         /// </summary>
22         public override Task OnDisconnectedAsync(Exception exception)
23         
24             var id = this.Context.ConnectionId;
25             var claimNameIdentifier = this.Context.User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.NameIdentifier)?.Value;
26             SignalRModel.SignalRList.Remove(id);
27             SignalRModel.StaticList.Remove(claimNameIdentifier);
28             return base.OnDisconnectedAsync(exception);
29         
30         /// <summary>
31         /// 发送消息
32         /// </summary>
33         /// <param name="user"></param>
34         /// <param name="message"></param>
35         /// <returns></returns>
36         public async Task SendMessage(string user, string message)
37         
38             await Clients.All.SendAsync("ReceiveMessage", user, message);
39         
40     

4、在程序启动的时候,把记录用户连接信息的类,注入成单例,保存用户和连接的对应关系,方便单个通信。

1   services.AddSingleton<SignalRModel>(provider =>
2   
3       return new SignalRModel();
4   );

5、配置

 1)、在ConfigureServices中加入

services.AddSignalR();//要写在addmvc()前面
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

 2)、在Configure中加入

app.UseMvc();
app.UseSignalR(routes => routes.MapHub<ChatHub>("/api/chatHub"); );//要写在UseMvc后面

6、这里我写了后端两个接口来发送消息,区别在于第一个是群发,第二个是针对一个连接发送的。

 1         [HttpGet("SendAll")]
 2         public IActionResult SendAll()
 3         
 4             _hubContext.Clients.All.SendAsync("ReceiveUpdate", "推送全部人").Wait();
 5             return Ok("推送全部人");
 6         
 7         [HttpGet("SendOnly")]
 8         public IActionResult SendOnly()
 9         
10             var claimNameIdentifier = User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.NameIdentifier)?.Value;
11             if (string.IsNullOrEmpty(claimNameIdentifier))
12             
13                 return Ok(new  code = ResultCode.NotLogin, message = "用户未登陆!" );
14             
15             _hubContext.Clients.Clients(claimNameIdentifier).SendAsync("ReceiveUpdate", DateTime.Now).Wait();
16             return Ok("推送当前登录用户");
17         

7、我项目实际用到的是这样的,给当前登录用户发送日志消息,判断连接是否断开,如果断开需要获取前面写的日志,发送给前端之后,把连接的状态改成连接中,后面就正常发送。

 1    foreach (var item in SignalRModel.SignalRList.Where(s => s.Value.Equals(userId.ToString())).ToList())
 2    
 3       if (SignalRModel.StaticList.Any(s => s.Key.Equals(userId.ToString()) && s.Value == SignalRStatus.Open))
 4       
 5          if (SignalRModel.StaticList.Any(s => s.Key.Equals(userId.ToString())))
 6          
 7               SignalRModel.StaticList.Remove(userId.ToString());
 8          
 9          SignalRModel.StaticList.Add(userId.ToString(), SignalRStatus.working);
10          _hubContext.Clients.Client(item.Key).SendAsync("ReceiveUpdate", FileHelper.ReadFile(Path.Combine(filePath, "tls_simplify.txt"), Encoding.UTF8)).Wait();
11       
12       _hubContext.Clients.Client(item.Key).SendAsync("ReceiveUpdate", args.Data).Wait();
13    

二、前端vue

1、安装依赖包

npm install @aspnet/signalr

2、示例页面

  1 <template>
  2     <section>
  3         <div style="display: none1">
  4             <el-form ref="form" label-width="80px" @submit.prevent="onSubmit"
  5                      style="margin:20px;width:60%;min-width:600px;">
  6                 <el-form-item label="用户名">
  7                     <el-input v-model="userName"></el-input>
  8                 </el-form-item>
  9                 <el-form-item label="密码">
 10                     <el-input v-model="userMessage"></el-input>
 11                 </el-form-item>
 12             </el-form>
 13             <ul v-for="(item, index) in messages" v-bind:key="index + ‘itemMessage‘">
 14                 <li><b>Name: </b>item.user</li>
 15                 <li><b>Message: </b>item.message</li>
 16             </ul>
 17             <p>
 18             <b>后台发送消息: </b>this.postMessage
 19             </p>
 20             <el-button type="primary" @click="submitCard">登录</el-button>
 21             <el-button type="primary" @click="getLogs">查询</el-button>
 22         </div>
 23     </section>
 24 </template>
 25 
 26 <script>
 27    
 28     import * as signalR from "@aspnet/signalr";
 29 
 30     export default 
 31       name: Dashboard,
 32         data() 
 33             return 
 34                 filters: 
 35                     LinkUrl: ‘‘
 36                 ,
 37                 listLoading: true,
 38                 postMessage: "",
 39                 userName: "Tom",
 40                 userMessage: "123",
 41                 connection: "",
 42                 messages: [],
 43                 t: ""
 44 
 45             
 46         ,
 47         methods: 
 48             getRoles() 
 49                 let thisvue=this;
 50                 let para = 
 51                     page: this.page,
 52                     key: this.filters.LinkUrl
 53                 ;
 54                 this.listLoading = true;
 55                 thisvue.connection.start().then(() => 
 56                    thisvue.connection.invoke(GetLatestCount, 1).catch(function (err) 
 57                    return console.error(err);
 58                 );
 59             );
 60             ,
 61             submitCard: function () 
 62                 if (this.userName && this.userMessage) 
 63                     this.connection.invoke(SendMessage, this.userName, this.userMessage).catch(function (err) 
 64                         return console.error(err);
 65                     );
 66 
 67                 
 68             ,
 69             getLogs: function () 
 70                 this.listLoading = true;
 71                 this.connection.invoke(GetLatestCount, 1).catch(function (err) 
 72                     return console.error(err);
 73                 );
 74             
 75         ,
 76         created: function () 
 77             let thisVue = this;
 78             thisVue.connection = new signalR.HubConnectionBuilder()
 79                 .withUrl(http://localhost:5000/api/chatHub)
 80                 .configureLogging(signalR.LogLevel.Information)
 81                 .build();
 82             thisVue.connection.on(ReceiveMessage, function (user, message) 
 83                 thisVue.messages.push(user, message);
 84             );
 85 
 86             thisVue.connection.on(ReceiveUpdate, function (update) 
 87                 console.info(update success!)
 88                 thisVue.listLoading = false;
 89                 thisVue.postMessage = update;
 90                 window.clearInterval(this.t)
 91             )
 92         ,
 93         mounted() 
 94             this.getRoles();
 95         ,
 96         beforeDestroy() 
 97             window.clearInterval(this.t)
 98             this.connection.stop();
 99         
100     
101 </script>
102 
103 <style scoped>
104     .demo-table-expand 
105         font-size: 0;
106     
107 
108     .demo-table-expand label 
109         width: 90px;
110         color: #99a9bf;
111     
112 
113     .demo-table-expand .el-form-item 
114         margin-right: 0;
115         margin-bottom: 0;
116         width: 30%;
117     
118 
119     .EXC 
120         color: red;
121     
122 </style>

 

以上是关于.net core 使用SignalR实现实时通信的主要内容,如果未能解决你的问题,请参考以下文章

.NETCOREASP.NET Core SignalR

ASP.NET Core SignalR:集线器Hubs

ASP.NET Core的实时库: SignalR简介及使用

ASP.NET Core SignalR实时推送配置,业务层实时推送SignalR消息

ASP.NET Core的实时库: SignalR -- 预备知识

.net core 3.0 Signalr - 实现一个业务推送系统