.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_ ...
随机推荐
- Apache Kylin在美团点评的应用
本文原载自大数据杂谈微信公众号. 感谢美团点评工程师高大月撰文并授权转载. 高大月,美团点评工程师,Apache Kylin PMC成员,目前主要在美团点评数据平台负责OLAP查询引擎的建设. 背 ...
- Greenplum 添加mirror步骤
原文链接:https://yq.aliyun.com/articles/695864 [TOC] 概述 新安装的greenplum集群只有primary节点,没有mirror.高可用性没得到保证.所以 ...
- 【转】跟我一起写 Makefile
概述—— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefi ...
- [SCOI2016]妖怪
嘟嘟嘟 离NOI最后一周,把自己容易忘的知识点和板子复习一下. (刚答完loj的笔试模拟,感觉上不了90--) update:哦,我89-- 先把式子写出来,每一个妖怪的战斗力\(S(i) = A + ...
- cgp的辣鸡比赛题解
目录 cgp的gcd 题目链接 思路 代码 cgp调戏妹子 题目链接 思路 代码 cgp的序列 题目链接 思路 代码 cgp的背包 题目链接 思路 代码 cgp的gcd 题目链接 传送门 思路 首先看 ...
- UOJ#318. 【NOI2017】蔬菜 贪心
原文链接 www.cnblogs.com/zhouzhendong/p/UOJ318.html 前言 我怎么越来越菜了.先是题目读错,想了个李超树假算法,然后读懂题之后没了耐心直接贺题.然后发现我数据 ...
- Android 照片上传
解释全在代码中: // 拍照上传 private OnClickListener mUploadClickListener = new OnClickListener() { public void ...
- 【CSP模拟赛】方程(数学)
题目描述 求关于x的方程:x1+x2+……xk=n的非负整数解的个数. 输入格式 仅一行,包含两个正整数n,k. 输出格式 一个整数,表示方程不同解的个数,这个数可能很大,你只需输出mod 20080 ...
- @Scope("prototype")的正确用法——解决Bean的多例问题
转自: https://www.jianshu.com/p/54b0711a8ec8 1. 问题,Spring管理的某个Bean需要使用多例 在使用了Spring的web工程中,除非特殊情况,我们 ...
- windows上hexo: command not found
使用hexo写博客已经有好几个月了,今天突然出现hexo: command not found,应该与我白天的时候调一下环境变量等有关.在对应的path添加环境变量,即可解决该问题.我的环境变量路径为 ...