SignalR实战,如何在.NET Framework和.NET Core中应用SignalR实现实时通信?
- 内容介绍
- 文章标签
- 相关推荐
本文共计3452个文字,预计阅读时间需要14分钟。
官方文档:ASP.NET Core SignalR 入门 | Microsoft LearnSignalR开源代码:SignalR · GitHub常见问题:在前后端分离项目中,后端是.NET Core,前端是Vue,如何使用SignalR?在前后端不分离项目中,如何使用.NE
官网文档:ASP.NET Core SignalR 入门 | Microsoft Learn
SignalR开源代码:SignalR · GitHub
很多小伙伴问:在前后端分离项目中,后端是.NET Core前端是Vue如何使用SignalR?在前后端不分离项目中,.NET Framework MVC项目中又如何使用SignalR技术呢?那就来看看下面这篇文章吧!本文主要介绍SignalR在实际项目中的应用,以及.NET Framework和.NET Core中如何去使用SignalR。
一、SignalR介绍
1.1-SignalR介绍
ASP.NET Core SignalR是一个开放源代码库,可用于简化向应用添加实时Web功能,实时Web功能使服务器端代码能够将内容推送到客户端。
1.2-SignalR的应用
- 需要从服务器进行高频更新的应用:包括游戏、社交网络、投票、拍卖、地图和GPS引用。
- 仪表盘和监视应用:包括公司仪表板、即时销售更新或旅行报警
- 协作应用:包括白板应用和团队会议软件。
- 通知应用:社交网络、电子邮件、聊天、游戏、旅行报警和其他应用都需要使用的通知。
二、.NET Framework使用SignalR
参考文献:
Owin介绍:www.cnblogs.com/Pinapple/p/6721361.html
Owin相关案例:1. 第一个 Owin 程序_microsoft.owin_bifan546的博客-CSDN博客
2.1-服务端(.NET Framework MVC)
(1)选择要使用Signalr的项目,点击。
(2)搜索包,找到这个后然后点击下载。
会自动安装四个,注意他们之间有依赖关系:
(3).NET Framework平台需要添加Owin相关的包。
OWIN 是一种定义 Web 服务器和应用程序组件之间的交互的规范 。这一规范的目的是发展一个广阔且充满活力的、基于 Microsoft .NET Framework 的 Web 服务器和应用程序组件生态系统。
Microsoft.Owin.Hosting
Microsoft.Owin.Cors
Microsoft.Owin.Host.HttpListener
(4)在Web项目(要使用的Signal)中创建一个文件。
using JiCai.Admin.Hubs;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(JiCai.Admin.Startup))]
namespace JiCai.Admin
{
public class Startup
{
/// <summary>
/// 应用程序配置
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
//启用SignalR
app.MapSignalR();
//绑定多个Hub
app.MapSignalR<DemoHub>("/demoHub");
}
}
}
例如:
(5)可以创建一个文件夹,专门放置Hub相关文件。[西瓜程序猿]这边是创建一个Hub文件,名为。
using Fenqibao.DTO;
using JiCai.Admin.Hubs.ConectionOperate;
using JiCai.Admin.Hubs.Models;
using log4net;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JiCai.Admin.Hubs
{
/// <summary>
/// 报表管理-总表Hub
/// </summary>
public class SummaryTableHub : PersistentConnection
{
public readonly BaseService _base = new BaseService();
private readonly ILog logger = LogManager.GetLogger(typeof(SummaryTableHub));
private ConnectionManagement summaryTableCon = new ConnectionManagement();
public CookieUserData LoginUserData
{
get
{
IOperator oper = ContainerManager.Resolve<IOperator>();
LoginUser loginUser = oper as LoginUser;
if (loginUser != null && loginUser.UserData != null)
{
return loginUser.UserData;
}
return null;
}
}
/// <summary>
/// 连接成功后调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnConnected(IRequest request, string connectionId)
{
//获得SignalR的连接id
var connid = connectionId;
//获得用户id
var userid = LoginUserData.Id.ToString();
Console.Write($":已建立连接!");
//判断一下用户是不是已经链接了
var checkUserConn = summaryTableCon.IsConn(connid, userid);
if (!checkUserConn)
{
//添加一个新的连接
summaryTableCon.AddConnInfo(new SignalRConn()
{
UserId = userid,
ConnectionId = connid
});
}
//更新连接
else
{
summaryTableCon.UpdateConnInfo(userid, connid);
}
return Connection.Send(connectionId, $"真正连接成功!");
//return base.OnConnected(request, connectionId);
}
/// <summary>
/// 接收到请求的时候调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="data"></param>
/// <returns></returns>
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
//获得用户id
var userid = LoginUserData.Id.ToString();
await Task.Factory.StartNew(async () =>
{
while (true)
{
var list = GetSummaryTableList(userid);
string json_jieshou_mes = "";
if (list != null && list.Count > 0)
{
json_jieshou_mes = JsonConvert.SerializeObject(list);
}
await Connection.Send(connectionId, json_jieshou_mes);
//每5秒同步一次
await Task.Delay(5000);
}
}, TaskCreationOptions.LongRunning);
//return base.OnReceived(request, connectionId, data);
}
/// <summary>
/// 连接中断的时候调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="stopCalled"></param>
/// <returns></returns>
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
Console.Write($":已断开连接!");
//获得SignalR的连接id
var connid = connectionId;
//关闭连接
summaryTableCon.DelConnInfo(connid);
return base.OnDisconnected(request, connectionId, stopCalled);
}
/// <summary>
/// 连接超时重新连接的时候调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnReconnected(IRequest request, string connectionId)
{
return base.OnReconnected(request, connectionId);
}
/// <summary>
/// 查询数据
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
private List<SummaryTableDataModel> GetSummaryTableList(string userId)
{
var result = _base.Query<SummaryTableDataModel>($@"
select * from demo-data
;
").ToList();
return result;
}
}
}
(6)在Hubs/ConectionOperate文件夹中,[西瓜程序猿]这边创建文件,用来管理所有连接。
using System.Collections.Generic;
using System.Linq;
namespace JiCai.Admin.Hubs.ConectionOperate
{
/// <summary>
/// 连接管理
/// </summary>
public class ConnectionManagement
{
/// <summary>
/// 用户连接集合
/// </summary>
public static List<SignalRConn> SignalRConns { get; set; } = new List<SignalRConn>();
/// <summary>
/// 添加连接
/// </summary>
/// <param name="conn"></param>
public void AddConnInfo(SignalRConn conn)
{
SignalRConns.Add(conn);
}
/// <summary>
/// 删除连接
/// </summary>
/// <param name="connid"></param>
public void DelConnInfo(string connid)
{
var signalRConns = SignalRConns.FirstOrDefault(u => u.ConnectionId == connid);
if (signalRConns != null)
{
SignalRConns.Remove(signalRConns);
}
}
/// <summary>
/// 更新链接(老的链接不起作用了)
/// 场景:客户端重连了,userid没变,但是connid变了
/// </summary>
/// <param name="userId">用户id</param>
/// <param name="newConnsId">新的链接id</param>
public void UpdateConnInfo(string userId, string newConnsId)
{
var signalRConns = SignalRConns.FirstOrDefault(u => u.UserId.ToLower() == userId.ToLower());
if (signalRConns != null)
{
signalRConns.ConnectionId = newConnsId;
}
}
/// <summary>
/// 判断用户是否已经链接
/// </summary>
/// <param name="connid">连接id</param>
/// <param name="userid">用户id</param>
/// <returns></returns>
public bool IsConn(string connid,string userid)
{
var userConn = SignalRConns.FirstOrDefault(u => u.ConnectionId.ToLower() == connid.ToLower() && u.UserId.ToLower() == userid.ToLower());
return userConn == null ? false : true;
}
}
}
(7)在Hubs/ConectionOperate文件夹中,创建文件用来作为SignalR和系统用户的连接实体。
namespace JiCai.Admin.Hubs.ConectionOperate
{
/// <summary>
/// 连接
/// </summary>
public class SignalRConn
{
/// <summary>
/// 系统用户id
/// </summary>
public string UserId { get; set; }
/// <summary>
/// SignleR链接Id(每次链接SignalR都会分配一个id)
/// </summary>
public string ConnectionId { get; set; }
}
}
2.2-客户端(JS)
(1)下载相关jq/signalr相关包,分别是和。可以访问下载(如果失效了,请联系我[西瓜程序猿])。
下载地址(编码:yRLCRp81):yongteng.lanzoub.com/iXDlu1631ugd
密码:44x5
文件截图:
(2)创建一个js文件,用来连接signalR。
// 连接服务
var connection = $.connection("/summary_table_hub");
// 建立链接
connection.start(function () {
//连接成功
console.log("西瓜程序猿-连接成功!");
//发送消息
connection.send("给我数据吧");
});
// 连接断开
connection.disconnected(function () {
console.log("西瓜程序猿-连接断开!");
});
// 接收服务器发来的消息
connection.received(function (data) {
console.log("西瓜程序猿-接收服务器发来的消息:");
console.log(data);
//显示数据
if (data != "" && checkJson(data)) {
var obj = JSON.parse(data);
var html_box = "";
for (var i = 0; i < obj.length; i++) {
html_box += `<tr>
<td>`+obj[i].project_name+`</td>
<td>`+ obj[i].zuori_sum+`</td>
<td>`+ obj[i].jinri_sum+`</td>
<td>`+ obj[i].qunian_sum+`</td>
<td>`+ obj[i].jinnian_sum+`</td>
<td>`+ obj[i].sum+`</td>
<td>`+ obj[i].yikaipiao_sum+`</td>
<td>`+ obj[i].weikaipiao_sum +`</td>
<td>`+ obj[i].yishoupiao_sum +`</td>
<td>`+ obj[i].weishoupiao_sum +`</td>
<td>`+ obj[i].kehu_yinghuikuan_sum+`</td>
<td>`+ obj[i].kehu_yihuikuan_sum+`</td>
<td>`+ obj[i].kehu_weihuikuan_sum +`</td>
<td>`+ obj[i].fuwu_yingfukuan_sum+`</td>
<td>`+ obj[i].fuwu_yifukuan_sum+`</td>
<td>`+ obj[i].fuwu_weifukuan_sum+`</td>
</tr>`
}
$("#last_async_date").text(new Date().toLocaleString());
$("#table_body").html(html_box);
}
});
//判断是不是json字符串
function checkJson(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
// 等于这个条件说明就是JSON字符串 会返回true
if (typeof obj == 'object' && obj) {
return true;
} else {
//不是就返回false
return false;
}
} catch (e) {
return false;
}
}
return false;
}
(3)创建要展示的文件,我这边是用MVC模式,所有前台文件是cshtml。
@{
ViewBag.Title = "西瓜程序猿-明细表";
}
@section styles{
<style>
.table_tr_center {
text-align: center !important;
}
.table_tr_bg_0 {
background: rgb(253,226,226);
}
.table_tr_bg_1 {
background: rgb(218,226,246);
}
.table_tr_bg_2 {
background: rgb(228,237,219);
}
.table_tr_bg_3 {
background: rgb(249,229,215);
}
</style>
}
@section scripts{
<script src="~/Scripts/jquery-1.6.4.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.3.js"></script>
<script src="~/Scripts/controller/hubs/data_list_table_hub.js?v=@DateTime.Now.Ticks"></script>
}
<div class="row">
<div class="col-xs-12">
</div>
<div class="col-xs-12">
<div>
报表最新同步时间:<span id="last_async_date" style="color: #FF5722 !important;"></span>
</div>
<div class="layui-form">
<table class="layui-table">
<colgroup>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th colspan="2" class="table_tr_center table_tr_bg_0">项目信息</th>
<th colspan="5" class="table_tr_center table_tr_bg_1">销售情况</th>
<th colspan="6" class="table_tr_center table_tr_bg_3">款项情况</th>
</tr>
<tr>
<th class="table_tr_center">项目名称</th>
<th class="table_tr_center">服务商名称</th>
<th class="table_tr_center">昨天订单总额</th>
<th class="table_tr_center">今天订单总额</th>
<th class="table_tr_center">去年订单总额</th>
<th class="table_tr_center">今年订单总额</th>
<th class="table_tr_center">订单总额</th>
<th class="table_tr_center">客户应回款总额</th>
<th class="table_tr_center">客户已回款总额</th>
<th class="table_tr_center">客户未回款总额</th>
<th class="table_tr_center">服务商应付款总额</th>
<th class="table_tr_center">服务商已付款总额</th>
<th class="table_tr_center">服务商未付款总额</th>
</tr>
</thead>
<tbody id="table_body">
</tbody>
</table>
</div>
</div>
</div>
(4)效果展示:
三、.NET Core WebAPI使用SignalR
场景:项目中需要服务端主动向客户端发送通知消息,后端是使用.NETCore实现的,前端是使用Vue3全家桶项目,前后端分离模式。本次主要讲使用SignalR如何来实现的。
3.1-服务端(.NET Core WebAPI)
1、右击项目,点击安装SignalR。
2、搜索,点击。
3、如果是.NET6以前的版本,在中配置:
如果是.NET6以后得版本,在配置:
var builder = WebApplication.CreateBuilder(args);
//添加SignalR服务
builder.Services.AddSignalR();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
//添加SignalR端点
endpoints.MapHub<ServerMonitorHub>("/serverMonitorHub");
});
4、创建SignalR中心
中心是一个类,用于处理客户端<——>服务器通信的高级管道。在SignalR_Demo项目文件夹中,创建Hubs文件夹。在Hubs文件夹中,使用已下代码创建ChatHub类。
public class ChatHub:Hub
{
/// <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);
}
}
3.2-客户端(Vue3+Vite+TS)
(1)安装SugbalR
npm install @latelier/vue-signalr
版本截图:
(2)然后新建一个文件,用来封装业务逻辑相关代码。[西瓜程序猿]是在目录下,创建了一个名为的文件,也可以是js文件,根据自己项目的需要去新建。
代码:
import * as signalR from '@microsoft/signalr';
//如果需要身份验证
//.withUrl('/messageHub', {accessTokenFactory: () => sessionStorage.getItem('token')})
let connection;
// 建立连接
async function start(url) {
try {
connection = new signalR.HubConnectionBuilder()
.withUrl(url)//跨域需要使用绝对地址
.configureLogging(signalR.LogLevel.Information)
.withAutomaticReconnect() // 设置自动重连机制
.build();
} catch(err) {
console.log(err);
setTimeout(start, 10000);//错误重连
}
}
// 开始signalr连接
const connect = async (url) => {
await start(url);
console.log(`:从服务器同步成功!`);
if(res) {
const result = JSON.parse(res);
getServerInfos(result);
}
});
// 开始连接
await connection.start();
});
// 卸载
onBeforeUnmount(() => {
// 断开连接
disconnect();
});
// 进度条颜色
const customColor = ref('#ff7831');
</script>
<style lang="scss" scoped>
.card-box {
padding-right: 15px;
margin-bottom: 15px;
}
:deep(.el-card.is-always-shadow) {
box-shadow: 0 5px 8px 0 rgba(0,0,0,0.03);
border: none;
}
.chart {
width: 100%;
height: 300px;
}
.box_item {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.table_tbody {
tr td{
padding: 15px 0;
text-align: center;
}
}
</style>
(5)效果展示:
版权声明:本文为原创文章,版权归 [西瓜程序猿] 所有,转载请注明出处,有任何疑问请私信咨询。
原文链接:blog.51cto.com/kimiliucn/7194470
本文共计3452个文字,预计阅读时间需要14分钟。
官方文档:ASP.NET Core SignalR 入门 | Microsoft LearnSignalR开源代码:SignalR · GitHub常见问题:在前后端分离项目中,后端是.NET Core,前端是Vue,如何使用SignalR?在前后端不分离项目中,如何使用.NE
官网文档:ASP.NET Core SignalR 入门 | Microsoft Learn
SignalR开源代码:SignalR · GitHub
很多小伙伴问:在前后端分离项目中,后端是.NET Core前端是Vue如何使用SignalR?在前后端不分离项目中,.NET Framework MVC项目中又如何使用SignalR技术呢?那就来看看下面这篇文章吧!本文主要介绍SignalR在实际项目中的应用,以及.NET Framework和.NET Core中如何去使用SignalR。
一、SignalR介绍
1.1-SignalR介绍
ASP.NET Core SignalR是一个开放源代码库,可用于简化向应用添加实时Web功能,实时Web功能使服务器端代码能够将内容推送到客户端。
1.2-SignalR的应用
- 需要从服务器进行高频更新的应用:包括游戏、社交网络、投票、拍卖、地图和GPS引用。
- 仪表盘和监视应用:包括公司仪表板、即时销售更新或旅行报警
- 协作应用:包括白板应用和团队会议软件。
- 通知应用:社交网络、电子邮件、聊天、游戏、旅行报警和其他应用都需要使用的通知。
二、.NET Framework使用SignalR
参考文献:
Owin介绍:www.cnblogs.com/Pinapple/p/6721361.html
Owin相关案例:1. 第一个 Owin 程序_microsoft.owin_bifan546的博客-CSDN博客
2.1-服务端(.NET Framework MVC)
(1)选择要使用Signalr的项目,点击。
(2)搜索包,找到这个后然后点击下载。
会自动安装四个,注意他们之间有依赖关系:
(3).NET Framework平台需要添加Owin相关的包。
OWIN 是一种定义 Web 服务器和应用程序组件之间的交互的规范 。这一规范的目的是发展一个广阔且充满活力的、基于 Microsoft .NET Framework 的 Web 服务器和应用程序组件生态系统。
Microsoft.Owin.Hosting
Microsoft.Owin.Cors
Microsoft.Owin.Host.HttpListener
(4)在Web项目(要使用的Signal)中创建一个文件。
using JiCai.Admin.Hubs;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(JiCai.Admin.Startup))]
namespace JiCai.Admin
{
public class Startup
{
/// <summary>
/// 应用程序配置
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
//启用SignalR
app.MapSignalR();
//绑定多个Hub
app.MapSignalR<DemoHub>("/demoHub");
}
}
}
例如:
(5)可以创建一个文件夹,专门放置Hub相关文件。[西瓜程序猿]这边是创建一个Hub文件,名为。
using Fenqibao.DTO;
using JiCai.Admin.Hubs.ConectionOperate;
using JiCai.Admin.Hubs.Models;
using log4net;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JiCai.Admin.Hubs
{
/// <summary>
/// 报表管理-总表Hub
/// </summary>
public class SummaryTableHub : PersistentConnection
{
public readonly BaseService _base = new BaseService();
private readonly ILog logger = LogManager.GetLogger(typeof(SummaryTableHub));
private ConnectionManagement summaryTableCon = new ConnectionManagement();
public CookieUserData LoginUserData
{
get
{
IOperator oper = ContainerManager.Resolve<IOperator>();
LoginUser loginUser = oper as LoginUser;
if (loginUser != null && loginUser.UserData != null)
{
return loginUser.UserData;
}
return null;
}
}
/// <summary>
/// 连接成功后调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnConnected(IRequest request, string connectionId)
{
//获得SignalR的连接id
var connid = connectionId;
//获得用户id
var userid = LoginUserData.Id.ToString();
Console.Write($":已建立连接!");
//判断一下用户是不是已经链接了
var checkUserConn = summaryTableCon.IsConn(connid, userid);
if (!checkUserConn)
{
//添加一个新的连接
summaryTableCon.AddConnInfo(new SignalRConn()
{
UserId = userid,
ConnectionId = connid
});
}
//更新连接
else
{
summaryTableCon.UpdateConnInfo(userid, connid);
}
return Connection.Send(connectionId, $"真正连接成功!");
//return base.OnConnected(request, connectionId);
}
/// <summary>
/// 接收到请求的时候调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="data"></param>
/// <returns></returns>
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
//获得用户id
var userid = LoginUserData.Id.ToString();
await Task.Factory.StartNew(async () =>
{
while (true)
{
var list = GetSummaryTableList(userid);
string json_jieshou_mes = "";
if (list != null && list.Count > 0)
{
json_jieshou_mes = JsonConvert.SerializeObject(list);
}
await Connection.Send(connectionId, json_jieshou_mes);
//每5秒同步一次
await Task.Delay(5000);
}
}, TaskCreationOptions.LongRunning);
//return base.OnReceived(request, connectionId, data);
}
/// <summary>
/// 连接中断的时候调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="stopCalled"></param>
/// <returns></returns>
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
Console.Write($":已断开连接!");
//获得SignalR的连接id
var connid = connectionId;
//关闭连接
summaryTableCon.DelConnInfo(connid);
return base.OnDisconnected(request, connectionId, stopCalled);
}
/// <summary>
/// 连接超时重新连接的时候调用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnReconnected(IRequest request, string connectionId)
{
return base.OnReconnected(request, connectionId);
}
/// <summary>
/// 查询数据
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
private List<SummaryTableDataModel> GetSummaryTableList(string userId)
{
var result = _base.Query<SummaryTableDataModel>($@"
select * from demo-data
;
").ToList();
return result;
}
}
}
(6)在Hubs/ConectionOperate文件夹中,[西瓜程序猿]这边创建文件,用来管理所有连接。
using System.Collections.Generic;
using System.Linq;
namespace JiCai.Admin.Hubs.ConectionOperate
{
/// <summary>
/// 连接管理
/// </summary>
public class ConnectionManagement
{
/// <summary>
/// 用户连接集合
/// </summary>
public static List<SignalRConn> SignalRConns { get; set; } = new List<SignalRConn>();
/// <summary>
/// 添加连接
/// </summary>
/// <param name="conn"></param>
public void AddConnInfo(SignalRConn conn)
{
SignalRConns.Add(conn);
}
/// <summary>
/// 删除连接
/// </summary>
/// <param name="connid"></param>
public void DelConnInfo(string connid)
{
var signalRConns = SignalRConns.FirstOrDefault(u => u.ConnectionId == connid);
if (signalRConns != null)
{
SignalRConns.Remove(signalRConns);
}
}
/// <summary>
/// 更新链接(老的链接不起作用了)
/// 场景:客户端重连了,userid没变,但是connid变了
/// </summary>
/// <param name="userId">用户id</param>
/// <param name="newConnsId">新的链接id</param>
public void UpdateConnInfo(string userId, string newConnsId)
{
var signalRConns = SignalRConns.FirstOrDefault(u => u.UserId.ToLower() == userId.ToLower());
if (signalRConns != null)
{
signalRConns.ConnectionId = newConnsId;
}
}
/// <summary>
/// 判断用户是否已经链接
/// </summary>
/// <param name="connid">连接id</param>
/// <param name="userid">用户id</param>
/// <returns></returns>
public bool IsConn(string connid,string userid)
{
var userConn = SignalRConns.FirstOrDefault(u => u.ConnectionId.ToLower() == connid.ToLower() && u.UserId.ToLower() == userid.ToLower());
return userConn == null ? false : true;
}
}
}
(7)在Hubs/ConectionOperate文件夹中,创建文件用来作为SignalR和系统用户的连接实体。
namespace JiCai.Admin.Hubs.ConectionOperate
{
/// <summary>
/// 连接
/// </summary>
public class SignalRConn
{
/// <summary>
/// 系统用户id
/// </summary>
public string UserId { get; set; }
/// <summary>
/// SignleR链接Id(每次链接SignalR都会分配一个id)
/// </summary>
public string ConnectionId { get; set; }
}
}
2.2-客户端(JS)
(1)下载相关jq/signalr相关包,分别是和。可以访问下载(如果失效了,请联系我[西瓜程序猿])。
下载地址(编码:yRLCRp81):yongteng.lanzoub.com/iXDlu1631ugd
密码:44x5
文件截图:
(2)创建一个js文件,用来连接signalR。
// 连接服务
var connection = $.connection("/summary_table_hub");
// 建立链接
connection.start(function () {
//连接成功
console.log("西瓜程序猿-连接成功!");
//发送消息
connection.send("给我数据吧");
});
// 连接断开
connection.disconnected(function () {
console.log("西瓜程序猿-连接断开!");
});
// 接收服务器发来的消息
connection.received(function (data) {
console.log("西瓜程序猿-接收服务器发来的消息:");
console.log(data);
//显示数据
if (data != "" && checkJson(data)) {
var obj = JSON.parse(data);
var html_box = "";
for (var i = 0; i < obj.length; i++) {
html_box += `<tr>
<td>`+obj[i].project_name+`</td>
<td>`+ obj[i].zuori_sum+`</td>
<td>`+ obj[i].jinri_sum+`</td>
<td>`+ obj[i].qunian_sum+`</td>
<td>`+ obj[i].jinnian_sum+`</td>
<td>`+ obj[i].sum+`</td>
<td>`+ obj[i].yikaipiao_sum+`</td>
<td>`+ obj[i].weikaipiao_sum +`</td>
<td>`+ obj[i].yishoupiao_sum +`</td>
<td>`+ obj[i].weishoupiao_sum +`</td>
<td>`+ obj[i].kehu_yinghuikuan_sum+`</td>
<td>`+ obj[i].kehu_yihuikuan_sum+`</td>
<td>`+ obj[i].kehu_weihuikuan_sum +`</td>
<td>`+ obj[i].fuwu_yingfukuan_sum+`</td>
<td>`+ obj[i].fuwu_yifukuan_sum+`</td>
<td>`+ obj[i].fuwu_weifukuan_sum+`</td>
</tr>`
}
$("#last_async_date").text(new Date().toLocaleString());
$("#table_body").html(html_box);
}
});
//判断是不是json字符串
function checkJson(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
// 等于这个条件说明就是JSON字符串 会返回true
if (typeof obj == 'object' && obj) {
return true;
} else {
//不是就返回false
return false;
}
} catch (e) {
return false;
}
}
return false;
}
(3)创建要展示的文件,我这边是用MVC模式,所有前台文件是cshtml。
@{
ViewBag.Title = "西瓜程序猿-明细表";
}
@section styles{
<style>
.table_tr_center {
text-align: center !important;
}
.table_tr_bg_0 {
background: rgb(253,226,226);
}
.table_tr_bg_1 {
background: rgb(218,226,246);
}
.table_tr_bg_2 {
background: rgb(228,237,219);
}
.table_tr_bg_3 {
background: rgb(249,229,215);
}
</style>
}
@section scripts{
<script src="~/Scripts/jquery-1.6.4.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.3.js"></script>
<script src="~/Scripts/controller/hubs/data_list_table_hub.js?v=@DateTime.Now.Ticks"></script>
}
<div class="row">
<div class="col-xs-12">
</div>
<div class="col-xs-12">
<div>
报表最新同步时间:<span id="last_async_date" style="color: #FF5722 !important;"></span>
</div>
<div class="layui-form">
<table class="layui-table">
<colgroup>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th colspan="2" class="table_tr_center table_tr_bg_0">项目信息</th>
<th colspan="5" class="table_tr_center table_tr_bg_1">销售情况</th>
<th colspan="6" class="table_tr_center table_tr_bg_3">款项情况</th>
</tr>
<tr>
<th class="table_tr_center">项目名称</th>
<th class="table_tr_center">服务商名称</th>
<th class="table_tr_center">昨天订单总额</th>
<th class="table_tr_center">今天订单总额</th>
<th class="table_tr_center">去年订单总额</th>
<th class="table_tr_center">今年订单总额</th>
<th class="table_tr_center">订单总额</th>
<th class="table_tr_center">客户应回款总额</th>
<th class="table_tr_center">客户已回款总额</th>
<th class="table_tr_center">客户未回款总额</th>
<th class="table_tr_center">服务商应付款总额</th>
<th class="table_tr_center">服务商已付款总额</th>
<th class="table_tr_center">服务商未付款总额</th>
</tr>
</thead>
<tbody id="table_body">
</tbody>
</table>
</div>
</div>
</div>
(4)效果展示:
三、.NET Core WebAPI使用SignalR
场景:项目中需要服务端主动向客户端发送通知消息,后端是使用.NETCore实现的,前端是使用Vue3全家桶项目,前后端分离模式。本次主要讲使用SignalR如何来实现的。
3.1-服务端(.NET Core WebAPI)
1、右击项目,点击安装SignalR。
2、搜索,点击。
3、如果是.NET6以前的版本,在中配置:
如果是.NET6以后得版本,在配置:
var builder = WebApplication.CreateBuilder(args);
//添加SignalR服务
builder.Services.AddSignalR();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
//添加SignalR端点
endpoints.MapHub<ServerMonitorHub>("/serverMonitorHub");
});
4、创建SignalR中心
中心是一个类,用于处理客户端<——>服务器通信的高级管道。在SignalR_Demo项目文件夹中,创建Hubs文件夹。在Hubs文件夹中,使用已下代码创建ChatHub类。
public class ChatHub:Hub
{
/// <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);
}
}
3.2-客户端(Vue3+Vite+TS)
(1)安装SugbalR
npm install @latelier/vue-signalr
版本截图:
(2)然后新建一个文件,用来封装业务逻辑相关代码。[西瓜程序猿]是在目录下,创建了一个名为的文件,也可以是js文件,根据自己项目的需要去新建。
代码:
import * as signalR from '@microsoft/signalr';
//如果需要身份验证
//.withUrl('/messageHub', {accessTokenFactory: () => sessionStorage.getItem('token')})
let connection;
// 建立连接
async function start(url) {
try {
connection = new signalR.HubConnectionBuilder()
.withUrl(url)//跨域需要使用绝对地址
.configureLogging(signalR.LogLevel.Information)
.withAutomaticReconnect() // 设置自动重连机制
.build();
} catch(err) {
console.log(err);
setTimeout(start, 10000);//错误重连
}
}
// 开始signalr连接
const connect = async (url) => {
await start(url);
console.log(`:从服务器同步成功!`);
if(res) {
const result = JSON.parse(res);
getServerInfos(result);
}
});
// 开始连接
await connection.start();
});
// 卸载
onBeforeUnmount(() => {
// 断开连接
disconnect();
});
// 进度条颜色
const customColor = ref('#ff7831');
</script>
<style lang="scss" scoped>
.card-box {
padding-right: 15px;
margin-bottom: 15px;
}
:deep(.el-card.is-always-shadow) {
box-shadow: 0 5px 8px 0 rgba(0,0,0,0.03);
border: none;
}
.chart {
width: 100%;
height: 300px;
}
.box_item {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.table_tbody {
tr td{
padding: 15px 0;
text-align: center;
}
}
</style>
(5)效果展示:
版权声明:本文为原创文章,版权归 [西瓜程序猿] 所有,转载请注明出处,有任何疑问请私信咨询。
原文链接:blog.51cto.com/kimiliucn/7194470

