SignalR in action: How to use SignalR in .NET Framework and .NET Core?

Official website documentation:Getting started with ASP.NET Core SignalR | Microsoft Learn

SignalR open source code:SignalR · GitHub

Table of contents

1. Introduction to SignalR

1.1-SignalR Introduction

1.2-Application of SignalR

2. .NET Framework uses SignalR

2.1-Server (.NET Framework MVC)

2.2-Client (JS)

3. .NET Core WebAPI uses SignalR

3.1-Server (.NET Core WebAPI)

3.2-Client (Vue3+Vite+TS)


Many friends asked: In a front-end and back-end separation project, the back end is .NET Core and the front end is Vue. How to use SignalR? In projects where front-end and back-end are not separated, how to use SignalR technology in .NET Framework MVC project? Then take a look at the article below! This article mainly introduces the application of SignalR in actual projects, and how to use SignalR in .NET Framework and .NET Core.

1. Introduction to SignalR

1.1-SignalR Introduction

ASP.NET Core SignalR is an open source library that can be used to simplify adding real-time web capabilities to your applications. Real-time web capabilities enable server-side code to push content to the client.

1.2-Application of SignalR

  • Applications that require high-frequency updates from the server: including games, social networks, polls, auctions, maps, and GPS references.
  • Dashboards and monitoring applications: including corporate dashboards, instant sales updates or travel alerts
  • Collaboration applications: including whiteboard applications and team conferencing software.
  • Notification Apps: Notifications for social networks, email, chat, games, travel alerts and other apps.

2. .NET Framework uses SignalR

references:

Owin介绍:https://www.cnblogs.com/Pinapple/p/6721361.html

Owin related cases:[Owin Learning Series] 1. The first Owin program_microsoft.owin_bifan546’s blog-CSDN blog

2.1-Server (.NET Framework MVC)

(1) Select the project to use Signalr and click [Manage NuGet Packages].

 

(2) Search for the [SignalR] package, find this and click to download.

Four will be installed automatically. Note that there are dependencies between them:

(3) The .NET Framework platform needs to add Owin-related packages.

OWIN is a specification that defines interactions between web servers and application components. The purpose of this specification is to develop a broad and vibrant ecosystem of Web servers and application components based on the Microsoft .NET Framework.

Microsoft.Owin.Hosting
Microsoft.Owin.Cors
Microsoft.Owin.Host.HttpListener

(4) Create a [Startup.cs] file in the Web project (Signal to be used).

using SignalrDemo.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");
        }
    }
}

For example:

(5) You can create a [Hubs] folder to specifically place Hub-related files. [Xigua Programmer] Here is a Hub file named [DemoHub.cs].

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 SignalrDemo.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($"【{connid}】:已建立连接!");

            //判断一下用户是不是已经链接了
            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, $"【用户:{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($"【{connectionId}】:已断开连接!");
            //获得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) In the Hubs/ConectionOperate folder, [Xigua Programmer] creates a [ConnectionManagement] file to manage all connections.

using System.Collections.Generic;
using System.Linq;

namespace SignalrDemo.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) In the Hubs/ConectionOperate folder, create the [SignalRConn.cs] file to serve as the connection entity between SignalR and system users.

namespace SignalrDemo.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-Client (JS)

(1) Download the relevant jq/signalr related packages, which are [jquery.signalR-2.4.3.js] and [jquery-1.6.4.min.js]. You can access the download (if it fails, please contact me [Xigua Programmer]).

Download address (encoding: yRLCRp81): https://yongteng.lanzoub.com/iXDlu1631ugd
Password: 44x5

File screenshot:

(2) Create a js file [data_list_table_hub.js] to connect to signalR.

// 连接服务
var connection = $.connection("/summary_table_hub");

// 建立链接
connection.start(function () {
    //连接成功
    console.log("西瓜程序猿-【" + new Date().toLocaleString() +"】连接成功!");
    //发送消息
    connection.send("给我数据吧");
});

// 连接断开
connection.disconnected(function () {
    console.log("西瓜程序猿-【" + new Date().toLocaleString() +"】连接断开!");
});

// 接收服务器发来的消息
connection.received(function (data) {
    console.log("西瓜程序猿-【" + new Date().toLocaleString() +"】接收服务器发来的消息:");
    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) Create the files to be displayed. I use MVC mode here, and all front-end files are 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/[email protected]"></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) Effect display:

3. .NET Core WebAPI uses SignalR

Scenario: In the project, the server needs to actively send notification messages to the client. The backend is implemented using .NETCore, and the frontend uses the Vue3 family bucket project, with the front-end and back-end separation mode. This time we mainly talk about how to implement it using SignalR.

3.1-Server (.NET Core WebAPI)

1. Right-click the project and click [Manage NuGet Packages] to install SignalR.

2. Search for [SignalR] and click [Install].

3. If it is a version before .NET6, configure in [Startup.cs]:

If it is a version after .NET6, configure it in [Program.cs]:

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. Create SignalR center

Hub is a class that handles the high-level pipeline of client-server communications. In the SignalR_Demo project folder, create the Hubs folder. In the Hubs folder, create the ChatHub class using the code below.

    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-Client (Vue3+Vite+TS)

(1) Install SugbalR

npm install @latelier/vue-signalr

Version screenshot:

(2) Then create a new file to encapsulate business logic related code. [Xigua Programmer] created a file named [signalr.ts] in the [src/utils] directory. It can also be a js file. You can create a new file according to the needs of your own project.

Code:

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(`【西瓜程序猿-${new Date().toLocaleString()}:SignalR已连接成功!`);
};

// 调用服务端方法
async function send(methodName, param){
  try {
    await connection.invoke(methodName, param);
  } catch (err) {
    console.error(err);
  }
}

//断开连接
const disconnect = async ()=>{
  await connection.stop();
  console.log(`【西瓜程序猿-${new Date().toLocaleString()}:SignalR已断开连接!`);
};

export {
  connection,
  connect,
  send,
  disconnect
};

(3) Then use the page. [Xigua Programmer] Here we take the Echarts chart display as an example. First, install the Echarts package.

npm install ejectors --save

Version screenshot:

(4) Then write the following code to the page. Modify and adjust the specific page style as needed.

<template>
  <!-- 面包屑导航 -->
  <breadcrumb class="breadcrumb_container" />
  <div class="app_main_padding">

    <el-row>

      <el-col :span="24" class="card-box">
        <el-card>
          <template #header>
            <span><i class="el-icon-monitor"></i> 服务器信息</span>
          </template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;">
              <tbody>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">主机名称</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.HostName}}</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">系统名称</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.OSDescription}}</div></td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">IP地址</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.IpAddress}}</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">操作系统</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.OperatingSystem}} {
   
   {serverInfo.OsArchitecture}}</div></td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>


      <el-col :span="24" class="card-box">
        <el-card>
          <template #header>
            <span><i class="el-icon-monitor"></i> 应用信息</span>
          </template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;">
              <tbody>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">.NET Core版本</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.FrameworkDescription}}</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">内存占用</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.MemoryFootprint}}</div></td>
                </tr>
                <tr>
                  <td class="el-table__cell is-leaf"><div class="cell">环境变量</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.EnvironmentName}}</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell">项目路径</div></td>
                  <td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{
   
   {serverInfo.ContentRootPath}}</div></td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>

      <el-col :span="24" class="card-box">
        <el-card>
          <template #header>
            <span><i class="el-icon-monitor"></i> 磁盘状态</span>
          </template>
          <div class="el-table el-table--enable-row-hover el-table--medium">
            <table cellspacing="0" style="width: 100%;" class="el-table__header">
              <thead>
                <tr>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">磁盘名称</div></th>
                  <th class="el-table_2_column_11 is-leaf headWeight el-table__cell"><div>盘符路径</div></th>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">文件系统</div></th>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">盘符类型</div></th>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">总大小</div></th>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">已用大小</div></th>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">可用大小</div></th>
                  <th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">已使用率</div></th>
                </tr>
              </thead>
              <tbody v-if="diskInfos" class="table_tbody">
                <tr v-for="(sysFile, index) in diskInfos" :key="index">
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.DiskName }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.RootPath }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.DriveType }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.FileSystem }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.TotalSize }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.UseSize }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell">{
   
   { sysFile.ResidueSize }}</div></td>
                  <td class="el-table_2_column_11 el-table__cell"><div class="cell"><el-progress :percentage="sysFile.UseRate" :text-inside="true" :stroke-width="14" :color="customColor"/></div></td>
                </tr>
              </tbody>
            </table>
          </div>
        </el-card>
      </el-col>




      <el-col :span="24" class="card-box">
        <el-card class="box-card">
          <template #header>
            <span><i class="el-icon-monitor"></i> 状态</span>
          </template>
          <div>
            <el-row>
              <el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
                <div class="title">CPU使用率</div>
                <div class="content">
                  <el-progress type="dashboard" :percentage="cpuInfo.CPULoadVal" :color="customColor" />
                </div>
          
                <div class="footer">{
   
   { cpuInfo.ProcessorCount }} 核心</div>
              </el-col>

              
              <el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
                <div class="title">内存使用率</div>
                <div class="content">
                  <el-progress type="dashboard" :percentage="memoryInfo.UsedPercentage" :color="customColor" />
                </div>
                <div class="footer">{
   
   { memoryInfo.UsedPhysicalMemory }} / {
   
   { memoryInfo.TotalPhysicalMemory }}</div>
              </el-col>


              <el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
                <div class="title">网络监控上传</div>
                <div class="content">
                  <el-progress type="dashboard" :percentage="networkInfo.SentSize" :color="customColor" >
                    <template #default>
                      {
   
   {networkInfo.SentSize}} {
   
   { networkInfo.SentSizeType }}
                    </template>
                  </el-progress>
                </div>
                <div class="footer"> {
   
   {networkInfo.SentSize}} {
   
   { networkInfo.SentSizeType }}/S</div>
              </el-col>


              <el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
                <div class="title">网络监控下载</div>
                <div class="content">
                  <el-progress type="dashboard" :percentage="networkInfo.ReceivedSize" :color="customColor" >
                    <template #default>
                      {
   
   {networkInfo.ReceivedSize}} {
   
   { networkInfo.ReceivedSizeType }}
                    </template>
                  </el-progress>
                </div>
                <div class="footer"> {
   
   {networkInfo.ReceivedSize}} {
   
   { networkInfo.ReceivedSizeType }}/S</div>
              </el-col>
            </el-row>
          </div>
        </el-card>
      </el-col>




      <el-col :span="24" class="card-box">
        <el-row :gutter="25">
            <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px">
              <el-card class="box-card">
                <template #header>
                  <span><i class="el-icon-monitor"></i> CPU使用率监控</span>
                </template>
                <div>
                  <div id="chart1" class="chart"></div>
                </div>
              </el-card>
            </el-col>
            <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px">
              <el-card class="box-card">
                <template #header>
                  <span><i class="el-icon-monitor"></i> 内存使用率监控</span>
                </template>
                <div>
                  <div id="chart2" class="chart"></div>
                </div>
              </el-card>
            </el-col>
          </el-row>
      </el-col>

    </el-row>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, reactive } from 'vue';
import { EChartsOption, init } from 'echarts';
import { connection, connect, disconnect } from '@/utils/signalr';
import { getApiUrl } from '@/apis/common/utils';

// CPU监控图标
const cpuOption = reactive<EChartsOption>(
  {
    tooltip: {
      trigger: 'axis'
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: []
    },
    yAxis: {
      type: 'value',
      min: 0,
      max: 100,
      interval: 20,
      axisLabel: {
        formatter: '{value}%'
      }
    },
    series: [
      {
        data: [],
        type: 'line'
      }
    ]
  }
);


const memoryOption = reactive<EChartsOption>(
  {
    tooltip: {
      trigger: 'axis'
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: []
    },
    yAxis: {
      type: 'value',
      min: 0,
      max: 100,
      interval: 20,
      axisLabel: {
        formatter: '{value}%'
      }
    },
    series: [
      {
        data: [],
        type: 'line'
      }
    ]
  }
);


// 获得服务器信息
const serverInfo = ref();
const cpuInfo = ref();
const memoryInfo = ref();
const diskInfos = ref([]);
const networkInfo = ref();

const getServerInfos = (res) => {
  serverInfo.value = res.Server;
  cpuInfo.value = res.CPU;
  memoryInfo.value = res.Memory;
  diskInfos.value = res.Disk;
  networkInfo.value = res.Network;

  if(cpuOption.xAxis.data.length >= 8) {
    cpuOption.xAxis.data.shift();
    cpuOption.series[0].data.shift();

    memoryOption.xAxis.data.shift();
    memoryOption.series[0].data.shift();
  }

  cpuOption.xAxis.data.push(res.Time);
  cpuOption.series[0].data.push(res.CPU.CPULoadVal);

  memoryOption.xAxis.data.push(res.Time);
  memoryOption.series[0].data.push(res.Memory.UsedPercentage);

  // 获取dom,断言HTMLElement类型,否则会报错
  const chartEle: HTMLElement = document.getElementById('chart1') as HTMLElement;
  const chart = init(chartEle);
  chart.setOption(cpuOption);

  // 获取dom,断言HTMLElement类型,否则会报错
  const chartEle2: HTMLElement = document.getElementById('chart2') as HTMLElement;
  const chart2 = init(chartEle2);
  chart2.setOption(memoryOption);

  // 重置图表大小
  window.addEventListener('resize', () => {
    chart.resize();
    chart2.resize();
  });
};

onMounted(async () => {
  // 建立连接
  connect('http://192.168.11:8080/serverMonitorHub');

  // 注册方法(接收服务器推送过来的数据)
  connection.on('ReceiveMessage', (res) => {
    console.log(`【${new Date().toLocaleString()}】:从服务器同步成功!`);
    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) Effect display:

Copyright statement: This article is an original article, and the copyright belongs to [Xigua Programmer]. Please indicate the source when reprinting. If you have any questions, please send a private message.

Original link:SignalR in practice: How to use SignalR in .NET Framework and .NET Core? _Xigua Programmer’s Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/2301_79251107/article/details/132429636