.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_ ...
随机推荐
- (尚004)Vue计算属性之基本使用和监视
所做效果预览: test004.html <!DOCTYPE html><html lang="en"><head> <meta char ...
- QSetting介绍
简介 QSettings类提供了持久的跨平台应用程序设置. 用户通常期望应用程序记住它的设置(窗口大小.位置等)所有会话.这些信息通常存储在Windows系统注册表,OS X和iOS的属性列表文件中. ...
- mock模拟后台数据
import Mock from 'mockjs' const Random = Mock.Random // 获取random对象,随机生成各种数据,具体请翻阅文档 const domain = ' ...
- printf的使用和test的使用
1.printf的使用 printf的转义序列 序列 说明 \a 警告字符,通常为ASCII的BEL字符 \b 后退 \c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字 ...
- cf 1051F 树+图
$des$给定一张 $n$ 个点 $m$ 条边的带权无向联通图,$q$ 次询问,每次询问 $u_i$ 到 $v_i$ 的最短路长度.$n,q <= 10^5, m - n <= 20$ $ ...
- 【一起来烧脑】一步学会JavaScript体系
[外链图片转存失败(img-b0GOhxRY-1563571645197)(https://upload-images.jianshu.io/upload_images/11158618-ba249b ...
- 谈谈对Spring的理解
转载自: https://blog.csdn.net/qq_41701956/article/details/90453716 Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而 ...
- Java设计模式之二工厂模式
在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模式,又 ...
- [转]重命名PostgreSQL数据库
初学PostgreSQL的朋友可能会有这样的疑惑:如何重命名已经建好的数据库?因为PostgreSQL默认的客户端pgAdmin III并没有地方可以让我们去修改某个现有的数据库的名称.遇到这个情况, ...
- NGINX实现咏南跨平台中间件集群
NGINX实现咏南跨平台中间件集群 首先要开启咏南LINUX中间件. 1)编辑usr/local/nginx/conf/nginx.conf #user nobody;worker_processe ...