.net mvc(C#)使用SignalR实时统计在线人数

signalr用于前后端的实时通信,语法简洁。但搞清楚原理需要付出一些时间。本文通过signalr实时统计系统在线人数,较读session、轮询等方法更新速度快、节省资源、结果准确

核心:通过重写SignalR的OnConnectedAsync事件统计登录人数、OnDisconnectedAsync事件统计下线人数。当然您也可以在以上两个事件中定义其他涉及登录、登出的内容,不只统计在线人数。具体步骤如下:

0.新建一个ASP.NET Core MVC项目

1.在项目中添加一个cs文件,用于建立SignalR中心,以提供实时处理登录、下线数据,及连接前端的管道。SignalR是aspnetcore框架自带的,因此无需引入新包。代码如下:

using Microsoft.AspNetCore.SignalR;
namespace WebApplication1.SignalRHubs
{
    public class StatisticOnline : Hub //继承自Microsoft.AspNetCore.SignalR.Hub
    {
        public static int onLine = 0; //用于记录在线人数
        public override async Task OnConnectedAsync() //登录(建立新的连接)时,人数加1,并向所有的用户发消息
        {
            onLine += 1;
            await Clients.All.SendAsync("ReceiveOnlineNo", onLine.ToString());
            await base.OnConnectedAsync();
        }
        public override async Task OnDisconnectedAsync(Exception? exception) //登出系统(连接断开)时,人数减1,并向所有的用户发消息
        {
            onLine -= 1;
            await Clients.All.SendAsync("ReceiveOnlineNo", onLine.ToString());
            Exception? temp = new Exception();
            await base.OnDisconnectedAsync(temp);
        }
    }
}

2.在program.cs中注册SignalR

(1/2)注册signalr,如下:

var builder = WebApplication.CreateBuilder(args); //在这句之后
builder.Services.AddSignalR(); //注册signalr中心,用于实时统计、显示在线人数
var app = builder.Build(); //在这句之前

(2/2)添加路由

var app = builder.Build();//在这句之后
app.MapHub<StatisticOnline>("/signalrhubs/StatisticOnline"); //其中“StatisticOnline”是signal R中的类的名字。“/signalrhubs/StatisticOnline”是用于拼接在.net mvc网站的域名后面,用于访问signalr中心的
app.Run(); //在这句之前

3.在前端添加一个标签,用于记录从管道中传过来的数据,如:

<label id="ststisticOnline" style="font-size:smaller;color:grey">人数</label>

4.在wwwroot里添加signalr.js文件,用于在前端使用signalr。具体方法可参考:

https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-8.0&WT.mc_id=dotnet-35129-website&tabs=visual-studio#add-the-signalr-client-library

中的“添加 SignalR 客户端库”章节。或者自己下载一个放在wwwroot中亦可

5.在前端引用第四步中添加的js库,如:

<script src="/microsoft-signalr/signalr.min.js"></script>

6.在前端编写连接signalr中心的js,并添加的window.onload中

<script>
    window.onload = async function () { //在页面启动后,即连接signalr
        await CreateSignalRConn();
    }
    async function CreateSignalRConn() {
        let signalRConn; //初始化连接的名称
        signalRConn = new signalR.HubConnectionBuilder().withUrl("https://域名(IP):端口(如需要)/signalrhubs/StatisticOnline").build(); //规定连接参数
        await signalRConn.start(); //启动连接
        
        signalRConn.on("ReceiveOnlineNo", (onLineNo) => { //监听signalr端口即可
            document.getElementById("ststisticOnline").innerHTML = "(当前在线:" + onLineNo + "人)"; //实时更新lable标签中的内容(显示当前在线人数)
        });
    }
</script>

然后启动项目,当在线的人数变化时,即可实时显示,如:

using System; using System.Data; using System.Text; namespace ZKXP.BLL { /// /// OnLine 的摘要说明。 /// public class OnLine { private string USERNAME; private int OFFLINEDIFF; private int REMOVEDIFF; public OnLine() { //直接在这里设定、或从配置文件中读取配置参数 ///存放用户名的Session名 USERNAME = "UserName"; ///多少分钟不活动的用户从在线列表中删除 OFFLINEDIFF = 5; ///多少秒执行一次删除不活动用户 REMOVEDIFF = 30; if(System.Web.HttpContext.Current.Application["OnlineTalbe"] == null) { this.CashTableInit(); } } public void CheckOnline() { //从Application获取数据表、获取SessionID DataTable dtOnline; dtOnline = (DataTable)System.Web.HttpContext.Current.Application["OnlineTalbe"]; string sessionId = System.Web.HttpContext.Current.Session.SessionID.ToString(); //数据表中是否有我的记录 DataRow drFind = dtOnline.Rows.Find(sessionId); if(drFind != null) { //有;更新我的状态 Info.Write("更新"); drFind["LastActiveTime"] = DateTime.Now; drFind["UserWhere"] = this.AtWhere; //用户由访客状态变为了登陆会员、或反之 if(Extend.GetSession(USERNAME) != null) { drFind["VisitorName"] = Extend.GetSession(USERNAME); drFind["VisitorLevel"] = Extend.GetSession("UserLevel"); } else { drFind["VisitorName"] = "vst"; drFind["VisitorLevel"] = -1; } } else { //无;加入关于我的在线信息 Info.Write("插入"); DataRow drNew = dtOnline.NewRow(); drNew["SessionID"] = sessionId; drNew["VisitorName"] = "vst"; drNew["VisitorLevel"] = -1; drNew["LastActiveTime"] = DateTime.Now; drNew["LoginTime"] = DateTime.Now; drNew["VisitorIP"] = Extend.GetRealIP();; drNew["UserWhere"] = this.AtWhere; dtOnline.Rows.Add(drNew); } //如果没有人正在执行删除且离上次删除的时间间隔超过设定值 TimeSpan tsRemove = DateTime.Now - Convert.ToDateTime(GetApplication("LastRemove")); if(tsRemove.Seconds > REMOVEDIFF && this.GetApplication("Removing").ToString() == "n") { //锁定,我正在删除过期用户 System.Web.HttpContext.Current.Application.Lock(); SetApplication("Removing", "y"); System.Web.HttpContext.Current.Application.UnLock(); //不知道Rows.Count是否随循环减少,如果是效率就大于foreach且这里不能使用foreach for(int i=0; i OFFLINEDIFF) { dtOnline.Rows.Remove(drDel); } } //我删完了,Response.Write("好累") ; System.Web.HttpContext.Current.Application.Lock(); SetApplication("Removing", "n"); SetApplication("LastRemove", DateTime.Now.ToString()); System.Web.HttpContext.Current.Application.UnLock(); } //把被我揉腻完了的数据表放回Application dtOnline.AcceptChanges(); System.Web.HttpContext.Current.Application.Lock(); System.Web.HttpContext.Current.Application["DataTalbeOnline"] = dtOnline; System.Web.HttpContext.Current.Application.UnLock(); } private string GetApplication(string apcname) { return System.Web.HttpContext.Current.Application[apcname].ToString(); } public void SetApplication(string apcname, string apcvalue) { System.Web.HttpContext.Current.Application[apcname] = apcvalue; } /// /// 返回用户当前位置 /// private string AtWhere { get { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(System.Web.HttpContext.Current.Request.ServerVariables["url"]); if(System.Web.HttpContext.Current.Request.ServerVariables["QUERY_STRING"] != String.Empty) { sb.Append("?"); sb.Append(System.Web.HttpContext.Current.Request.ServerVariables["QUERY_STRING"]); } return sb.ToString() ; } } /// /// 创建表 /// public void CashTableInit() { DataTable dt = new DataTable("OnlineTalbe"); dt.Columns.Add("SessionID",typeof(string)); dt.Columns.Add("VisitorName", typeof(string)); dt.Columns.Add("VisitorLevel", typeof(int)); dt.Columns.Add("LastActiveTime", typeof(DateTime)); dt.Columns.Add("LoginTime", typeof(DateTime)); dt.Columns.Add("VisitorIP", typeof(string)); dt.Columns.Add("UserWhere", typeof(string)); dt.Columns["SessionID"].Unique = true; dt.PrimaryKey = new DataColumn[]{dt.Columns["SessionID"]}; System.Web.HttpContext.Current.Application["OnlineTalbe"] = dt; System.Web.HttpContext.Current.Application["LastRemove"] = DateTime.Now.ToString(); System.Web.HttpContext.Current.Application["Removing"] = "n"; } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值