这几天在研究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实现实时通信的更多相关文章

  1. 一步一步学习SignalR进行实时通信_1_简单介绍

    一步一步学习SignalR进行实时通信\_1_简单介绍 SignalR 一步一步学习SignalR进行实时通信_1_简单介绍 前言 SignalR介绍 支持的平台 相关说明 OWIN 结束语 参考文献 ...

  2. asp.net core 使用 signalR(一)

    asp.net core 使用 signalR(一) Intro SignalR 是什么? ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实 ...

  3. 一步一步学习SignalR进行实时通信_8_案例2

    原文:一步一步学习SignalR进行实时通信_8_案例2 一步一步学习SignalR进行实时通信\_8_案例2 SignalR 一步一步学习SignalR进行实时通信_8_案例2 前言 配置Hub 建 ...

  4. 一步一步学习SignalR进行实时通信_9_托管在非Web应用程序

    原文:一步一步学习SignalR进行实时通信_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信\_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信_9_托管在非We ...

  5. 一步一步学习SignalR进行实时通信_7_非代理

    原文:一步一步学习SignalR进行实时通信_7_非代理 一步一步学习SignalR进行实时通信\_7_非代理 SignalR 一步一步学习SignalR进行实时通信_7_非代理 前言 代理与非代理 ...

  6. 一步一步学习SignalR进行实时通信_5_Hub

    原文:一步一步学习SignalR进行实时通信_5_Hub 一步一步学习SignalR进行实时通信\_5_Hub SignalR 一步一步学习SignalR进行实时通信_5_Hub 前言 Hub命名规则 ...

  7. 一步一步学习SignalR进行实时通信_6_案例

    原文:一步一步学习SignalR进行实时通信_6_案例 一步一步学习SignalR进行实时通信\_6_案例1 一步一步学习SignalR进行实时通信_6_案例1 前言 类的定义 各块功能 后台 上线 ...

  8. 一步一步学习SignalR进行实时通信_4_Hub

    原文:一步一步学习SignalR进行实时通信_4_Hub 一步一步学习SignalR进行实时通信\_4_Hub SignalR 一步一步学习SignalR进行实时通信_4_Hub 前言 创建Hub 配 ...

  9. 一步一步学习SignalR进行实时通信_3_通过CORS解决跨域

    原文:一步一步学习SignalR进行实时通信_3_通过CORS解决跨域 一步一步学习SignalR进行实时通信\_3_通过CORS解决跨域 SignalR 一步一步学习SignalR进行实时通信_3_ ...

随机推荐

  1. Xilinx ISE的时序约束

    使用Synplify Pro加时序约束.综合完毕后,可以在ISE中进行布局.布线.需要用.ucf文件指定布局布线的时钟约束.前者可以比后者小. 早期的ISE,两个约束可以继承.现在用的高版本,反而需要 ...

  2. Pytest权威教程21-API参考-03-夹具(Fixtures)

    目录 夹具(Fixtures) @ pytest.fixture config.cache的 capsys capsysbinary capfd capfdbinary doctest_namespa ...

  3. Leetcode84. 柱状图中最大的矩形(单调栈)

    84. 柱状图中最大的矩形 前置 单调栈 做法 连续区间组成的矩形,是看最短的那一块,求出每一块左边第一个小于其高度的位置,右边也同理,此块作为最短限制.需要两次单调栈 单调栈维护递增区间,每次不满足 ...

  4. SpringCloud:Ribbon负载均衡

    1.概述 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端       负载均衡的工具. 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客 ...

  5. postman上传excel,java后台读取excel生成到指定位置进行备份,并且把excel中的数据添加到数据库

    最近要做个前端网页上传excel,数据直接添加到数据库的功能..在此写个读取excel的demo. 首先新建springboot的web项目 导包,读取excel可以用poi也可以用jxl,这里本文用 ...

  6. Spark(二)—— 标签计算、用户画像应用

    一.标签计算 数据 86913510 {"reviewPics":[],"extInfoList":null,"expenseList":n ...

  7. sem_init重复调用引发sem_wait线程无法被唤醒

    问题 一段老代码,两个线程,一个线程调用sem_wait等待信号量,另外一个线程在某失败分支会调用sem_init清信号量,结果导致sem_wait线程无法被唤醒: 分析 Linux manpage ...

  8. T-MAX组--项目冲刺(第五天)

    T-MAX组--项目冲刺(第五天) THE FIFTH DAY 项目相关 作业相关 具体描述 所属班级 2019秋福大软件工程实践Z班 作业要求 团队作业第五次-项目冲刺 作业正文 T-MAX组--项 ...

  9. 从库延迟增大,MySQL日志出现InnoDB: page_cleaner: 1000ms intended loop took 17915ms.

    今天同事负责的数据库从库出现从库延迟增大,MySQL日志InnoDB: page_cleaner: 1000ms intended loop took 17915ms. 了解原因,keepalived ...

  10. 8款超好用的SVG编辑工具用起来

    随着响应式网页的发展,对于内容呈现的要求也越来越高,尤其是图像.为了在各种设备上能实现自然伸缩或扩展而不影响图片质量,所以矢量图形(SVG)正变得越来越受欢迎. 大家都知道,在计算机图形学中,有两种主 ...