.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_ ...
随机推荐
- Postgresql 进程和内存结构
在本章中,总结了PostgreSQL中的流程体系结构和内存体系结构,以帮助阅读后续章节.如果您已经熟悉它们,可以跳过本章 1.进程结构 Postgresql 是一个C/S架构的关系型数据库,由多个后台 ...
- 用es实现模糊搜索
Haystack为Django提供了模块化的搜索.它的特点是统一的,熟悉的API,可以让你在不修改代码的情况下使用不同的搜索后端(比如 Solr, Elasticsearch, Whoosh, Xap ...
- 阿里开源线上应用调试利器 Arthas的背后
Arthas是一个功能非常强大的诊断工具,功能点很多,例如:jvm信息.线程信息.搜索类中的方法.跟踪代码执行.观测方法的入参和返回参数等等. 作为有追求的程序员,你不仅要知道它能做什么,更要思考它是 ...
- 机器学习---用python实现感知机算法和口袋算法(Machine Learning PLA Pocket Algorithm Application)
之前在<机器学习---感知机(Machine Learning Perceptron)>一文中介绍了感知机算法的理论知识,现在让我们来实践一下. 有两个数据文件:data1和data2,分 ...
- Maven 异常 druid jar冲突
异常: 十二月 25, 2017 11:04:41 下午 org.apache.tomcat.util.digester.SetPropertiesRule begin 警告: [SetPropert ...
- SpringCloud:Zipkin链路追踪,并将数据写入mysql
1.zipkin server 1.1.新建Springboot项目,zinkin 1.2.添加依赖 <dependency> <groupId>io.zipkin.java& ...
- bootstrap select 多选的用法,取值和赋值(取消默认选择第一个的对勾)
h5自带的select标签可以实现按住ctrl键多选的功能,但是样式及其难看. bootstrap select是很好用的前端插件 首先引入bootstrap和bootstrap-select的c ...
- Coupled和segregated【转载】
转载自:http://blog.sina.com.cn/s/blog_67873f6c0100ltq6.html 问题1: 我看中文帮组里说是'分离'的意思?我绝对翻译不太好,请问有更好的翻译吗? 和 ...
- python操作toml文件
# -*- coding: utf-8 -*- # @Time : 2019-11-18 09:31 # @Author : cxa # @File : toml_demo.py # @Softwar ...
- Windows下基于IIS服务的SSL服务器的配置
Windows下基于IIS服务的SSL服务器的配置 实验环境 Windows Server 2008 R1(CA) Windows Server 2008 R2(web服务器) Windows 7 x ...