![be2dddc48fec34ade56d567fdfff1d8b.png](https://i-blog.csdnimg.cn/blog_migrate/991cd34396294473967985312e257861.jpeg)
前面介绍了几篇如何将http://Asp.Net Core、WPF、Unity客户端中的Debug日志记录通过SignalR发送到远程日志监控端的分享。大家可能也看出来了,NebuLog并不是一个完善规划、有清晰产品思路的项目,而是一个出于技术探索的蜻蜓点水式的即兴项目,旨在通过在微软各种技术中实现NebuLog的过程来学习相关技术的结构、运行流程。
那么很自然地我就想到用WPF客户端来做监控工具是怎样一种体验。前面见过,因为我对Html5+JavaScript的了解非常有限,因此在web客户端中存在性能问题。而WPF我相对更熟悉一些,更重要的是,我也想比较一下,现在编译式的Javascript在浏览器中运行的速度能否与基于XAML的接近于原生客户端的速度相媲美?
我觉得桌面应用程序还是存在一些市场的,比如我们熟悉的工具Fiddler、Postman、SourceTree等,尽管普遍认为现在HTML将来一统天下的可能性非常大,甚至有人认为微软已经放弃了XMAL。从WPF向.NET Core和.Net 5靠拢的速度来看,也确实有这种可能,但是至少WPF目前已经支持了.Net Core,并且对.NET 5的支持也在微软规划的路线中,因此可能还有一些盼头。
思路
NebuLogWpfServerSample项目直接包含在NebuLogServerSamples解决方案中,用以代替MVC版本的监控服务端程序。同样,我还是选择了基于.Net Core框架的WPF来生成一个WPF客户端程序。而基于SignalR的NebuLogHub,并不需要另外启动一个iis网站来提供服务,而是直接让WPF来做Hub的宿主。
如果按照我所知道的做法,一般可以用web服务、self-host等方法来为SignalR提供宿主,以前我用WCF时也曾经使用Windows Service方式,应该也适用于SignalR。不过,经过查阅资料,发现可以用WPF来宿主一个WebHost,然后在其中配置SignalR的方式。这与http://Asp.net Core网站项目的结构很像,因此决定采用这种模式。
WPF为http://ASP.NET Core和SignalR提供宿主服务
为了让WPF提供Web服务,我参考了StackOverflow上的一篇博文:
WPF SignalR Serverstackoverflow.com![d3352d9d9c871e9ffa07982179a2a78f.png](https://i-blog.csdnimg.cn/blog_migrate/e92404a7bebb5910b5eb455db44feabd.png)
这篇文章提供了一种WPF种宿主IHost,基于http://asp.net core 3.1框架的,也就包含了SignalR服务。代码如下:
public partial class App : Application
{
private IServiceProvider serviceProvider;
private IHost _host;
public App()
{
IServiceCollection services = new ServiceCollection();
if (_host!=null) _host.Dispose();
_host = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder => webBuilder
.UseUrls("http://*:5999")
.ConfigureServices(services =>
{
services.AddSignalR().AddMessagePackProtocol();
services.AddSingleton<MainWindow>();
})
.Configure(app =>
{
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapHub<NebuLogHub>("/NebuLogHub"));
}))
.Build();
_host.Start();
}
}
是不是有点眼熟的样子。
而ConfigureServices和Confugure方法都简化了,实际上只要配置NebuLogHub的路由信息即可(如果服务端本身不需要向外发送日志信息)。
然后,把App.xaml中的标签改掉:
<......
Startup="OnStartup"
Exit="OnExit">
这样,App执行完构造函数后,就会运行OnStartup回调,这里就可以向DI框架去请求MainWindow的实例并启动窗体了。
protected void OnStartup(object sender, StartupEventArgs e)
{
var mainWindow = _host.Services.GetRequiredService<MainWindow>();
mainWindow.Show();
}
MainWindow - 监控界面视图
MainWindow被启动的时候,实际上IHost服务已经在运行,NebuLogHub已经在监听状态。我们需要做的是把NebuLogHub收到消息后触发的几个事件注册一下回调响应,然后可以在回调中提供相应的视图刷新动作即可。
public MainWindow(IServiceProvider services, ILoggerFactory factory) : base()
{
NebuLogHub.OnILoggingMessageReceived += OnLoggingMessageReceived;
NebuLogHub.OnAddStatRequestReceived += OnAddStatRequestReceived;
NebuLogHub.OnRefreshStatRequestReceived += OnRefreshStatRequestRecieved;
InitializeComponent();
}
由于我打开WPF的XAML界面时立即感受到一种强烈的冲击:卧槽,XAML这么复杂,几年前攒下的一点点知识已经忘。。。光。。。光。。。勒!
于是我当即决定,实现接收Log消息后立马撤退。
测试
我们还是用NebuLogMvcSample作为测试的客户端来发送日志。
![0f05eb2e8a78e31f3d97d9e26ba4ffd3.png](https://i-blog.csdnimg.cn/blog_migrate/e34135b8594ac94e0f3eaa6417e04ce6.jpeg)
为了实现刷刷刷的感觉还是牺牲了一些视频性能(用DataGrid.ScrollTo在每次收到消息后都去刷新以达到滚动效果),但是数据达到3000条后基本还是能跑。相比之下,http://Asp.Net Core MVC的示例中数据到了1000多条基本就装死了,不过页面中基于Bootstrap Table的表格进行了滚动、按时间排序等重度任务,所以WPF和浏览器的性能也难以从这两个简单的项目来进行性能比较。
不过WPF毕竟还是原生的桌面应用,通过后台C#可以对数据进行各种灵活的处理,可能这也是WPF存在的理由之一吧。