工作上有个业务,.Net Core WebAPI作为服务端,需要将运行过程中产生的日志分类,并实时推送到各种终端进行报警,终端有桌面(WPF)、移动(Xamarin.Forms)、网站(Angular.JS)等,使用SignalR进行警报日志推送。

微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏。

https://dotnet9.com

阅读导航

  1. 本文背景

  2. 代码实现

  3. 本文参考

1.本文背景

工作上有个业务,.Net Core WebAPI作为服务端,需要将运行过程中产生的日志分类,并实时推送到各种终端进行报警,终端有桌面(WPF)、移动(Xamarin.Forms)、网站(Angular.JS)等,使用SignalR进行警报日志推送。

下面是桌面端的测试效果:

2.代码实现

整个系统由服务端、桌面端、网站、移动端组成,结构如下:

2.1 服务端与客户端都使用的日志实体类

简单的日志定义,服务端会主动将最新日志通过AlarmLogItem实例推送到各个终端:

/// <summary>
/// 报警日志
/// </summary>
public class AlarmLogItem
{public string Id { get; set; }/// <summary>/// 日志类型/// </summary>public AlarmLogType Type { get; set; }/// <summary>/// 日志名称/// </summary>public string Text { get; set; }/// <summary>/// 日志详细信息/// </summary>public string Description { get; set; }/// <summary>/// 日志更新时间/// </summary>public string UpdateTime { get; set; }
}public enum AlarmLogType
{Info,Warn,Error
}

2.2 服务端

使用 .Net Core 2.2 搭建的Web API项目

2.2.1 集线器类AlarmLogHub.cs

定义集线器Hub类AlarmLogHub,继承自Hub,用于SignalR通信,看下面的代码,没加任何方法,您没看错:

public class AlarmLogHub : Hub
{}

2.2.2 Startup.cs

需要在此类中注册SignalR管道及服务,在下面两个关键方法中用到,B/S后端的朋友非常熟悉了。

  1. ConfigureServices方法

添加SignalR管道(是这个说法吧?):

services.AddSignalR(options => { options.EnableDetailedErrors = true; });
  1. Configure方法注册SignalR服务地址

端口用的8022,客户端访问地址是:http://localhost:8022/alarmlog

app.UseSignalR(routes =>
{routes.MapHub<AlarmLogHub>("/alarmlog");
});

2.2.3 SignalRTimedHostedService.cs

这是个关键类,用于服务端主动推送日志使用,Baidu、Google好久才找到,站长技术栈以C/S为主,B/S做的不多,没人指点,心酸,参考网址:How do I push data from hub to client every second using SignalR 。

该类继承自IHostedService,作为服务自启动(乱说的),通过SignalRTimedHostedService 的构造函数依赖注入得到IHubContext<AlarmLogHub>的实例,用于服务端向各客户端推送日志使用(在StartAsync方法中开启定时器,模拟服务端主动推送警报日志,见 DoWork 方法):

internal class SignalRTimedHostedService : IHostedService, IDisposable
{private readonly IHubContext<AlarmLogHub> _hub;private Timer _timer;//模拟发送报警日志List<AlarmLogItem> lstLogs = new List<AlarmLogItem> {new AlarmLogItem{ Type=AlarmLogType.Error,Text="OK WebSocket断连",Description="尝试连接50次,未成功重连!"},new AlarmLogItem{ Type=AlarmLogType.Warn,Text="OK WebSocket断开重连",Description="尝试连接5次,成功重连!"},new AlarmLogItem{ Type=AlarmLogType.Warn,Text="OK Restfull断连",Description="尝试连接30次,成功重连!"},new AlarmLogItem{ Type=AlarmLogType.Error,Text="OK WebSocket断连",Description="第一次断开链接!"},new AlarmLogItem{ Type=AlarmLogType.Info,Text="OK WebSocket连接成功",Description="首次成功连接!"},new AlarmLogItem{ Type=AlarmLogType.Error,Text="OK WebSocket断连",Description="尝试连接第7次,未成功重连!"}};Random rd = new Random(DateTime.Now.Millisecond);public SignalRTimedHostedService(IHubContext<AlarmLogHub> hub){_hub = hub;}public Task StartAsync(CancellationToken cancellationToken){_timer = new Timer(DoWork, null, TimeSpan.Zero,TimeSpan.FromSeconds(1));return Task.CompletedTask;}private void DoWork(object state){if (DateTime.Now.Second % rd.Next(1, 3) == 0){AlarmLogItem log = lstLogs[rd.Next(lstLogs.Count)];log.UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");_hub.Clients.All.SendAsync("ReceiveAlarmLog", log);}}public Task StopAsync(CancellationToken cancellationToken){_timer?.Change(Timeout.Infinite, 0);return Task.CompletedTask;}public void Dispose(){_timer?.Dispose();}
}

SignalRTimedHostedService 类作为Host服务(继承自 IHostedService),需要在Startup.cs的ConfigureServices方法中注册管道(是吧?各位有没有B/S比较好的书籍推荐,站长打算有空好好学学):

services.AddHostedService<SignalRTimedHostedService>();

服务端关键代码已经全部奉上,下面主要说说桌面端和移动端代码,其实两者代码类似。

2.3 网站

参考 index.html

2.4 桌面端(WPF)

使用 .Net Core 3.0创建的WFP工程,需要引入Nuget包:Microsoft.AspNetCore.SignalR.Client

界面用一个ListView展示收到的日志:

<Grid><ListBox x:Name="messagesList"  RenderTransformOrigin="-0.304,0.109" BorderThickness="1" BorderBrush="Gainsboro"/>
</Grid>

后台写的简陋,直接在窗体构造函数中连接服务端SignalR地址:http://localhost:8022/alarmlog, 监听服务端警报日志推送:ReceiveAlarmLog。

using AppClient.Models;
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Threading.Tasks;
using System.Windows;namespace SignalRChatClientCore
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{HubConnection connection;public MainWindow(){InitializeComponent();connection = new HubConnectionBuilder().WithUrl("http://localhost:8022/alarmlog").Build();connection.Closed += async (error) =>{await Task.Delay(new Random().Next(0, 5) * 1000);await connection.StartAsync();};connection.On<AlarmLogItem>("ReceiveAlarmLog", (message) =>{this.Dispatcher.Invoke(() =>{messagesList.Items.Add(message.Description);});});try{connection.StartAsync();messagesList.Items.Add("Connection started");}catch (Exception ex){messagesList.Items.Add(ex.Message);}}}
}

2.4 移动端

移动端其实和桌面端类似,因为桌面端使用的 .Net Core 3.0,移动端使用的 .NET Standard 2.0,都需要引入Nuget包:Microsoft.AspNetCore.SignalR.Client。

界面使用ListView展示日志,这就不贴代码了,使用的MVVM方式,直接贴ViewModel代码吧,大家只看个大概,不要纠结具体代码,参照桌面.cs代码,是不是一样的?

using AppClient.Models;
using AppClient.Views;
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
using System.Linq;namespace AppClient.ViewModels
{/// <summary>/// 报警日志VM/// </summary>public class AlarmItemsViewModel : BaseViewModel{private ViewState _state = ViewState.Disconnected;/// <summary>/// 报警日志列表/// </summary>public ObservableCollection<AlarmLogItem> AlarmItems { get; set; }public Command LoadItemsCommand { get; set; }//连接报警服务端private HubConnection _connection;public AlarmItemsViewModel(){Title = "报警日志";AlarmItems = new ObservableCollection<AlarmLogItem>();LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());//收到登录成功通知MessagingCenter.Subscribe<LoginViewModel, LoginUser>(this, "LoginSuccess", async (sender, userInfo) =>{//DisplayAlert("登录成功", userInfo.UserName, "确定");});MessagingCenter.Subscribe<NewItemPage, AlarmLogItem>(this, "添加项", async (obj, item) =>{var newItem = item as AlarmLogItem;AlarmItems.Add(newItem);await DataStore.AddItemAsync(newItem);});ConnectAlarmServer();}async Task ExecuteLoadItemsCommand(){if (IsBusy)return;IsBusy = true;try{AlarmItems.Clear();var items = await DataStore.GetItemsAsync(true);foreach (var item in items){AlarmItems.Add(item);}}catch (Exception ex){Debug.WriteLine(ex);}finally{IsBusy = false;}}private async Task ConnectAlarmServer(){if (_state == ViewState.Connected){try{await _connection.StopAsync();}catch (Exception ex){return;}_state = ViewState.Disconnected;}else{try{_connection = new HubConnectionBuilder().WithUrl(App.Setting.AlarmHost).Build();_connection.On<AlarmLogItem>("ReceiveAlarmLog", async (newItem) =>{AlarmItems.Add(newItem);await DataStore.AddItemAsync(newItem);});_connection.Closed += async (error) =>{await Task.Delay(new Random().Next(0, 5) * 1000);await _connection.StartAsync();};await _connection.StartAsync();}catch (Exception ex){return;}_state = ViewState.Connected;}}private enum ViewState{Disconnected,Connecting,Connected,Disconnecting}}
}

关键代码已经贴完了,希望对大家能有所帮助。

3.参考

  1. .NET 客户端 SignalR ASP.NET Core

  2. SignalR-samples

  3. How do I push data from hub to client every second using SignalR

除非注明,文章均由 Dotnet9 整理发布,欢迎转载。

转载请注明本文地址:https://dotnet9.com/6913.html

欢迎扫描下方二维码关注 Dotnet9 的微信公众号,本站会及时推送最新技术文章(微信公众号“dotnet9_com”):

Dotnet9.com

使用SignalR从服务端主动推送警报日志到各种终端(桌面、移动、网页)相关推荐

  1. flux服务器推消息,服务端主动推送数据,除了 WebSocket 你还能想到啥?

    原标题:服务端主动推送数据,除了 WebSocket 你还能想到啥? 来自公众号: 江南一点雨 在 上篇文章 中,松哥和大家分享了 WebFlux 的基本用法,小伙伴们已经了解到使用 WebFlux ...

  2. Asp.net SignalR 实现服务端消息推送到Web端

    参考博客https://www.cnblogs.com/wintersun/p/4148223.html ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的W ...

  3. spring集成mina,包含心跳检测,实现服务端主动推送

    服务端 1.常规的spring工程集成mina时,pom.xml中需要加入如下配置: <dependency><groupId>org.slf4j</groupId> ...

  4. Netty-Server-Hander自定义解码器-服务端主动推送

    netty server端使用自定义解码器,通过存储client连接实现主动推送消息,并发送自定义心跳包 Server端 依赖 <dependency><groupId>io. ...

  5. 服务端主动推送数据,除了 WebSocket 你还能想到啥?

    在上篇文章中,松哥和大家分享了 WebFlux 的基本用法,小伙伴们已经了解到使用 WebFlux 我们的返回值可以是 Mono 也可以是 Flux,如果是 Flux,由于 Flux 中包含多个元素, ...

  6. 利用mochiweb让服务端主动推送数据至前端页面

    对于智能化监控软件,从wincc等国外的有相当积累的系统,以及国内一些小型的智能化集成软件,通常其监控数据通过前端绑定控件的方式,做到了实时的通讯,通过控件直接和后端服务交互.这种方式可以灵活的组态, ...

  7. 服务端如何推送消息给客户端?

    大家好,我是前端西瓜哥,今天带大家了解一下服务端如何推送消息给客户端. 有时候,我们希望服务端能够主动推送一些信息给客户端.但 HTTP 协议只能让客户端发起请求然后服务端响应,而无法让服务端主动去发 ...

  8. pushlet实现单机-集群服务端消息推送

    一.什么是pushlet? 1.pushlet推送是一种将java后台数据推送到web页面的框架技术,实现了comet. 2.comet是一个用于描述客户端和服务器之间交互的术语,即使用长期保持的ht ...

  9. SSE 服务端消息推送

    SSE(Server-sent events) SSE 它是基于 HTTP 协议的,一般意义上的 HTTP 协议是无法做到服务端主动向客户端推送消息的.有一种变通方法,就是服务器向客户端声明,发送的是 ...

最新文章

  1. 敏捷研发落地之持续集成
  2. 有限状态机(使用状态模式C++实现)
  3. Winform中实现颜色拾取器获取RGB与16进制颜色程序与源码分享
  4. 很好的阻止了事件的发生_请定好您的闹钟,八月,夜空中将发生这13件超酷的天文事件...
  5. 人类跌落梦境显示无法连接服务器,人类跌落梦境手游进不去闪退怎么办 人类跌落梦境无法进入解决方法...
  6. 特征编码1 - 特征编码概述与分类
  7. linux下安装rar解压包
  8. java中三种方法_Java文件I/O的三种方法
  9. NPM酷库:minimatch,模式匹配字符串
  10. 三种实例化bean方式——Spring对bean的管理(一)
  11. 用极大似然法估计因子载荷矩阵_关于因子分析|stata
  12. 一个合格的全栈工程师应该具备哪些技能?
  13. 2021-7-19 fact函数求阶乘的用法
  14. 行频、场频与分辨率、刷新率
  15. 《人生的智慧》——人所拥有的财产
  16. 中国电子学会2022年12月份青少年软件编程Python等级考试试卷三级真题(含答案)
  17. 微信公众号留言功能实现方法分享
  18. 重庆华南城开业运营发布会暨华南城APP上线仪式圆满成功
  19. mvc原理和mvc模式的优缺点
  20. F1C100S电阻触摸屏驱动

热门文章

  1. 【F12一下,看看页面里的第一行】——说说浏览器兼容性模式
  2. ipad和iphone切图_如何在iPhone,iPad和Mac上使消息静音
  3. facebook 分享页面_Facebook个人资料,页面和组之间有什么区别?
  4. log4net日志插件的使用
  5. linux命令chown和chmod什么区别
  6. 红帽linux5安装Oracle 9i enterprise
  7. 通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存...
  8. .NET Core 如何调试 CPU 爆高?
  9. Dapr牵手.NET学习笔记:跨物理机负载均衡服务调用
  10. 基于事件驱动架构构建微服务第4部分:repositories