.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、声明一个类来记录用户的连接信息。
public class SignalRModel
{
public static Dictionary<string, SignalRStatus> StaticList = new Dictionary<string, SignalRStatus>();
public static Dictionary<string, string> SignalRList { get; set; } = new Dictionary<string, string>();
}
3、声明Hub,这里我重写了连接和断开方法,用来绑定用户和连接的ConnectionId。(这个比较复杂,是因为我程序中执行的第三方程序,需要实时输出当前执行的程序的日志。但是调用的执行不可能直接写在控制器里,这样调用我没办法获取当前用户的登录Id。然后我就在发起连接和断开连接的方法处理了。)
public class ChatHub : Hub
{
/// <summary>
/// 连接成功
/// </summary>
/// <returns></returns>
public override Task OnConnectedAsync()
{
var id = this.Context.ConnectionId;
var claimNameIdentifier = this.Context.User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.NameIdentifier)?.Value;
SignalRModel.SignalRList.Add(id, claimNameIdentifier);
if (SignalRModel.StaticList.Any(s => s.Key.Equals(claimNameIdentifier)))
{
SignalRModel.StaticList.Remove(claimNameIdentifier);
}
SignalRModel.StaticList.Add(claimNameIdentifier, SignalRStatus.Open);
return base.OnConnectedAsync();
}
/// <summary>
/// 断开连接
/// </summary>
public override Task OnDisconnectedAsync(Exception exception)
{
var id = this.Context.ConnectionId;
var claimNameIdentifier = this.Context.User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.NameIdentifier)?.Value;
SignalRModel.SignalRList.Remove(id);
SignalRModel.StaticList.Remove(claimNameIdentifier);
return base.OnDisconnectedAsync(exception);
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="user"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
4、在程序启动的时候,把记录用户连接信息的类,注入成单例,保存用户和连接的对应关系,方便单个通信。
services.AddSingleton<SignalRModel>(provider =>
{
return new SignalRModel();
});
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、这里我写了后端两个接口来发送消息,区别在于第一个是群发,第二个是针对一个连接发送的。
[HttpGet("SendAll")]
public IActionResult SendAll()
{
_hubContext.Clients.All.SendAsync("ReceiveUpdate", "推送全部人").Wait();
return Ok("推送全部人");
}
[HttpGet("SendOnly")]
public IActionResult SendOnly()
{
var claimNameIdentifier = User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(claimNameIdentifier))
{
return Ok(new { code = ResultCode.NotLogin, message = "用户未登陆!" });
}
_hubContext.Clients.Clients(claimNameIdentifier).SendAsync("ReceiveUpdate", DateTime.Now).Wait();
return Ok("推送当前登录用户");
}
7、我项目实际用到的是这样的,给当前登录用户发送日志消息,判断连接是否断开,如果断开需要获取前面写的日志,发送给前端之后,把连接的状态改成连接中,后面就正常发送。
foreach (var item in SignalRModel.SignalRList.Where(s => s.Value.Equals(userId.ToString())).ToList())
{
if (SignalRModel.StaticList.Any(s => s.Key.Equals(userId.ToString()) && s.Value == SignalRStatus.Open))
{
if (SignalRModel.StaticList.Any(s => s.Key.Equals(userId.ToString())))
{
SignalRModel.StaticList.Remove(userId.ToString());
}
SignalRModel.StaticList.Add(userId.ToString(), SignalRStatus.working);
_hubContext.Clients.Client(item.Key).SendAsync("ReceiveUpdate", FileHelper.ReadFile(Path.Combine(filePath, "tls_simplify.txt"), Encoding.UTF8)).Wait();
}
_hubContext.Clients.Client(item.Key).SendAsync("ReceiveUpdate", args.Data).Wait();
}
二、前端vue
1、安装依赖包
npm install @aspnet/signalr
2、示例页面
<template>
<section>
<div style="display: none1">
<el-form ref="form" label-width="80px" @submit.prevent="onSubmit"
style="margin:20px;width:60%;min-width:600px;">
<el-form-item label="用户名">
<el-input v-model="userName"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="userMessage"></el-input>
</el-form-item>
</el-form>
<ul v-for="(item, index) in messages" v-bind:key="index + 'itemMessage'">
<li><b>Name: </b>{{item.user}}</li>
<li><b>Message: </b>{{item.message}}</li>
</ul>
<p>
<b>后台发送消息: </b>{{this.postMessage}}
</p>
<el-button type="primary" @click="submitCard">登录</el-button>
<el-button type="primary" @click="getLogs">查询</el-button>
</div>
</section>
</template> <script> import * as signalR from "@aspnet/signalr"; export default {
name: 'Dashboard',
data() {
return {
filters: {
LinkUrl: ''
},
listLoading: true,
postMessage: "",
userName: "Tom",
userMessage: "",
connection: "",
messages: [],
t: "" }
},
methods: {
getRoles() {
let thisvue=this;
let para = {
page: this.page,
key: this.filters.LinkUrl
};
this.listLoading = true;
thisvue.connection.start().then(() => {
thisvue.connection.invoke('GetLatestCount', ).catch(function (err) {
return console.error(err);
});
});
},
submitCard: function () {
if (this.userName && this.userMessage) {
this.connection.invoke('SendMessage', this.userName, this.userMessage).catch(function (err) {
return console.error(err);
}); }
},
getLogs: function () {
this.listLoading = true;
this.connection.invoke('GetLatestCount', ).catch(function (err) {
return console.error(err);
});
}
},
created: function () {
let thisVue = this;
thisVue.connection = new signalR.HubConnectionBuilder()
.withUrl('http://localhost:5000/api/chatHub')
.configureLogging(signalR.LogLevel.Information)
.build();
thisVue.connection.on('ReceiveMessage', function (user, message) {
thisVue.messages.push({user, message});
}); thisVue.connection.on('ReceiveUpdate', function (update) {
console.info('update success!')
thisVue.listLoading = false;
thisVue.postMessage = update;
window.clearInterval(this.t)
})
},
mounted() {
this.getRoles();
},
beforeDestroy() {
window.clearInterval(this.t)
this.connection.stop();
}
}
</script> <style scoped>
.demo-table-expand {
font-size: ;
} .demo-table-expand label {
width: 90px;
color: #99a9bf;
} .demo-table-expand .el-form-item {
margin-right: ;
margin-bottom: ;
width: %;
} .EXC {
color: red;
}
</style>
.net core 使用SignalR实现实时通信的更多相关文章
- 一步一步学习SignalR进行实时通信_1_简单介绍
一步一步学习SignalR进行实时通信\_1_简单介绍 SignalR 一步一步学习SignalR进行实时通信_1_简单介绍 前言 SignalR介绍 支持的平台 相关说明 OWIN 结束语 参考文献 ...
- asp.net core 使用 signalR(一)
asp.net core 使用 signalR(一) Intro SignalR 是什么? ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实 ...
- 一步一步学习SignalR进行实时通信_8_案例2
原文:一步一步学习SignalR进行实时通信_8_案例2 一步一步学习SignalR进行实时通信\_8_案例2 SignalR 一步一步学习SignalR进行实时通信_8_案例2 前言 配置Hub 建 ...
- 一步一步学习SignalR进行实时通信_9_托管在非Web应用程序
原文:一步一步学习SignalR进行实时通信_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信\_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信_9_托管在非We ...
- 一步一步学习SignalR进行实时通信_7_非代理
原文:一步一步学习SignalR进行实时通信_7_非代理 一步一步学习SignalR进行实时通信\_7_非代理 SignalR 一步一步学习SignalR进行实时通信_7_非代理 前言 代理与非代理 ...
- 一步一步学习SignalR进行实时通信_5_Hub
原文:一步一步学习SignalR进行实时通信_5_Hub 一步一步学习SignalR进行实时通信\_5_Hub SignalR 一步一步学习SignalR进行实时通信_5_Hub 前言 Hub命名规则 ...
- 一步一步学习SignalR进行实时通信_6_案例
原文:一步一步学习SignalR进行实时通信_6_案例 一步一步学习SignalR进行实时通信\_6_案例1 一步一步学习SignalR进行实时通信_6_案例1 前言 类的定义 各块功能 后台 上线 ...
- 一步一步学习SignalR进行实时通信_4_Hub
原文:一步一步学习SignalR进行实时通信_4_Hub 一步一步学习SignalR进行实时通信\_4_Hub SignalR 一步一步学习SignalR进行实时通信_4_Hub 前言 创建Hub 配 ...
- 一步一步学习SignalR进行实时通信_3_通过CORS解决跨域
原文:一步一步学习SignalR进行实时通信_3_通过CORS解决跨域 一步一步学习SignalR进行实时通信\_3_通过CORS解决跨域 SignalR 一步一步学习SignalR进行实时通信_3_ ...
随机推荐
- TPC-H 下载参考
CSDN免费下载地址 tpc-h-v2.17.3.zip tools https://download.csdn.net/download/zes2014/10558251
- 本地Windows远程桌面连接阿里云Ubuntu服务器
本地Windows远程桌面连接阿里云Ubuntu 16.04服务器: 1.目的:希望通过本地的Windows远程桌面连接到阿里云的Ubuntu服务器,通过远程桌面图形界面的方式操作服务器. 2.条件: ...
- gitconfig别名配置
vim ~/.gitconfig 进行配置 [user] name = Your Name email = you@yourdomain.example.com [core] editor = vim ...
- 利用JDK方式和GuavaAPI方式实现观察者模式
1.JDK方法实现案例需求: 去餐厅吃饭有时候需要排队,进行排队叫号.假如所有等待的人都是观察者,叫号系统就是一个被监听的主题对象.当叫号系统发出叫号通知后,所有等待的人,都会收到通知,然后检查自己的 ...
- RabbitMQ入门学习系列(七) 远程调用RPC
快速阅读 生产者和消费者启动以后,都有一个接收事件,消费者是接收事件是处理调用方法以后等待生产者的返回,生产者的接收事件是处理接收生产者发送的消息,进行处理.消费者发送的时候要在回调队列中加入一个标识 ...
- 【多线程与并发】:Java中的锁
锁的概念 锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁可以防止多个线程同时访问共享资源(但有些锁可以允许多个线程并发的访问共享资源,如读写锁). 在JDK1.5之前,Java是通过sync ...
- SQL查询练习题
1.查询学生"百里守约"的基本信息 select * from students where name='百里守约' 2.查询学生百里守约"或"百里玄策&quo ...
- LITEIDE配置
LITEIDE配置 工具--管理GOPATH 工具--编辑当前环境
- Java hashCode与equals学习
1.关于Object类的equals方法的特点 a) 自反性: x.equals(x) 应该返回true b) 对称性: x.equals(y)为true,那么y.equals(x) 也为true c ...
- pt-table-checksum解读【转】
pt-table-checksum是目前可以说是最好的查看主从一致性的工具 先来个使用例子,有助快速上手使用 在主库执行: mysql>GRANT SELECT, PROCESS, SUPER, ...