ASP.NET Core实时库SignalR简单应用

  • ASP.NET Core实时库SignalR简单应用已关闭评论
  • 117 次浏览
  • A+
所属分类:.NET技术
摘要

SignalR 是用于构建需要实时用户交互或实时数据更新的Web 应用程序的一个开放源代码.NET 库。不仅仅用在Web应用中,后面会讲到它的应用范围。它简化了简化了构建实时应用程序的过程,包括ASP.NET Server库和JavaScript Client库,以便管理Client与Server连接并将内容更新推送给Client。


一、什么是SignalR:

SignalR 是用于构建需要实时用户交互或实时数据更新的Web 应用程序的一个开放源代码.NET 库。不仅仅用在Web应用中,后面会讲到它的应用范围。它简化了简化了构建实时应用程序的过程,包括ASP.NET Server库和JavaScript Client库,以便管理Client与Server连接并将内容更新推送给Client。

SignalR可用于需要实时刷新获取后台数据的程序。常用的场景范围有:社交应用程序、 多用户游戏、 业务协作和新闻,天气或财务更新应用程序等等。
ASP.NET Core实时库SignalR简单应用

二、关于WebSocket知识拓展:

在传统的HTTP中,只能客户端主动向服务器端发起请求,服务器端无法主动向客户端发送消息。有的业务场景下,我们需要服务器端主动向客户端发送消息,比如Web聊天室、OA系统、站内消息等。

为了实现服务器端向客户端推送消息,在2008年诞生了WebSocket协议,并且该协议在2011年成为国际标准。目前所有的主流浏览器都已经支持WebSocket协议。WebSocket基于TCP(transmission control protocol,传输控制协议),支持二进制通信,因此通信效率非常高,它可以让服务器处理大量的并发WebSocket连接;WebSocket是双工通信,因此服务器可以高效地向客户端推送消息。

三、建立SignalR服务端:

项目架构:

ASP.NET Core实时库SignalR简单应用

集线器服务定义:

  /// <summary>     /// 定义集线器     /// </summary>     public class MyHub : Hub     {         /// <summary>         /// 用户字典         /// </summary>         private static Dictionary<string, string> dictUsers = new Dictionary<string, string>();          /// <summary>         /// 建立连接回调         /// </summary>         /// <returns></returns>         public override Task OnConnectedAsync()         {             Console.WriteLine($"ID:{Context.ConnectionId} 已连接");             return base.OnConnectedAsync();         }          /// <summary>         /// 断开连接回调         /// </summary>         /// <param name="exception"></param>         /// <returns></returns>         public override Task OnDisconnectedAsync(Exception? exception)         {             Console.WriteLine($"ID:{Context.ConnectionId} 已断开");             return base.OnDisconnectedAsync(exception);         }           /// <summary>         /// 登录功能,将用户ID和ConntectionId关联起来         /// </summary>         /// <param name="userId"></param>         public void Login(string userId)         {             if (!dictUsers.ContainsKey(userId))             {                 dictUsers[userId] = Context.ConnectionId;             }             Console.WriteLine($"{userId}登录成功,ConnectionId={Context.ConnectionId}");             //向所有用户发送当前在线的用户列表             Clients.All.SendAsync("Users", dictUsers.Keys.ToList());         }          /// <summary>         /// 退出功能,当客户端退出时调用         /// </summary>         /// <param name="userId"></param>         public void Logout(string userId)         {             if (dictUsers.ContainsKey(userId))             {                 dictUsers.Remove(userId);             }             Console.WriteLine($"{userId}退出成功,ConnectionId={Context.ConnectionId}");         }      } 

实时推送任务定义:

 /// <summary>     /// 定义定时任务     /// </summary>     public class MyWorker     {         /// <summary>         /// 单例         /// </summary>         public static MyWorker Instance;         /// <summary>         /// 锁         /// </summary>         private static readonly object locker = new object();         /// <summary>         /// 集线器请求上下文         /// </summary>         private IHubContext<MyHub> context;         /// <summary>         /// 定时器         /// </summary>         public static System.Timers.Timer timer;          /// <summary>         /// 构造注入         /// </summary>         /// <param name="context"></param>         public MyWorker(IHubContext<MyHub> context)         {             this.context = context;             timer = new System.Timers.Timer(1000);//单位毫秒             timer.Enabled = true;             timer.AutoReset = true;//自动重新             timer.Elapsed += Timer_Elapsed;             timer.Start();         }          /// <summary>         /// 时钟到达事件         /// </summary>         /// <param name="sender"></param>         /// <param name="e"></param>         private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)         {             //模拟数据,一般情况下,从数据库获取,然后通知到客户端             Dictionary<string, object> data = new Dictionary<string, object>();             var online = new Random().Next(0, 100);             var male = Math.Floor(new Random().NextSingle() * online);             var female = online - male;             data["online"] = online;             data["male"] = male;             data["female"] = female;             context.Clients.All.SendAsync("Data", data);         }          /// <summary>         /// 单例注册服务         /// </summary>         /// <param name="context"></param>         public static void Register(IHubContext<MyHub> context)         {             if (Instance == null)             {                 lock (locker)                 {                     if (Instance == null)                     {                         Instance = new MyWorker(context);                     }                 }             }         }     } 

全局注册SignaIR服务:

using Microsoft.AspNetCore.SignalR; using SignalRApi.Hubs; using SignalRApi.Jobs;  var builder = WebApplication.CreateBuilder(args);  // Add services to the container.  builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();  //1.添加注册SignalR服务 builder.Services.AddSignalR();  var app = builder.Build();  // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) {     app.UseSwagger();     app.UseSwaggerUI(); }  //使用路由 app.UseRouting(); app.UseHttpsRedirection(); app.UseAuthorization();  //在Use中注册单例实例 app.Use(async (context, next) => {     var hubContext = context.RequestServices                             .GetRequiredService<IHubContext<MyHub>>();     MyWorker.Register(hubContext);//调用静态方法注册      if (next != null)     {         await next.Invoke();     } }); app.MapControllers();  //2.映射路由 app.UseEndpoints(endpoints => {     endpoints.MapHub<MyHub>("/myhub");//启用SignalR中间件,并且设置当客户端通过SignalR请求“/myhub”这个路径的时候,由ChatHub进行处理。 });   app.Run();  

四、建立SignalR客户端:

客户端界面设计:

ASP.NET Core实时库SignalR简单应用

客户端依赖:

客户端下载安装Nuget包:Microsoft.AspNetCore.SignalR.Client

dotnet add package Microsoft.AspNetCore.SignalR.Client --version 6.0.8 

客户端代码—点击事件定义:

        #region 点击事件          /// <summary>         /// 建立连接         /// </summary>         /// <param name="sender"></param>         /// <param name="e"></param>         private void btConnect_Click(object sender, EventArgs e)         {             //1.初始化             InitInfo();             //2.监听             Listen();             //3.连接             Link();             //4.登录             Login();         }          /// <summary>         ///断开连接         /// </summary>         /// <param name="sender"></param>         /// <param name="e"></param>         private void btDistinct_Click(object sender, EventArgs e)         {             hubConnection.InvokeAsync("Logout", "12345");             _isDistinct = true;         }         #endregion 

客户端代码—SignaIR连接与监听定义:

        #region 连接和监听         /// <summary>         /// 是否断开连接         /// </summary>         private bool _isDistinct = false;          /// <summary>         /// 集线器连接对象         /// </summary>         private HubConnection hubConnection;          /// <summary>         /// 初始化Connection对象         /// </summary>         private void InitInfo()         {          hubConnection = new HubConnectionBuilder().WithUrl("http://localhost:5275/myhub").WithAutomaticReconnect().Build();//必须和在服务器端MapHub注册单例实例设置的路径一致;             hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);         }          /// <summary>         /// 监听         /// </summary>         private void Listen()         {             hubConnection.On<Dictionary<string, object>>("Data", ReceiveInfos);         }          /// <summary>         /// 连接         /// </summary>         private async void Link()         {             try             {                 await hubConnection.StartAsync();//建立完成一个客户端到集线器的连接。             }             catch (Exception ex)             {                 MessageBox.Show(ex.Message);             }         }         /// <summary>         /// /监听事件         /// </summary>         /// <param name="data"></param>          private void ReceiveInfos(Dictionary<string, object> data)         {             if (data == null || data.Count < 1 || _isDistinct)             {                 return;             }             this.tbOnline.Text = data["online"]?.ToString();             this.tbMale.Text = data["male"]?.ToString();             this.tbFemale.Text = data["female"]?.ToString();         }         /// <summary>        /// 登录        /// </summary>         private void Login()         {             hubConnection.InvokeAsync("Login", "12345");             _isDistinct =false;         }         #endregion 

五、运行演示:

启动服务:

ASP.NET Core实时库SignalR简单应用

启动客户端:

ASP.NET Core实时库SignalR简单应用

接收实时数据推送:

ASP.NET Core实时库SignalR简单应用

服务端控制台打印输出:

ASP.NET Core实时库SignalR简单应用

源码链接地址:

Gitee完整项目实例地址:

https://gitee.com/mingliang_it/SignalRDemo