• .NET Core学习笔记(5)——WebAPI从Server端push消息到Client


    标题起得有点厉害,汉字夹杂着E文,不符合教育部公布的“向社会推荐使用的外语词中文译名”规范。不过他管不着我。写本篇的起因,是重构一个现有的WinForms程序,将Server端的部分逻辑从raw socket通讯的方式,改为调用WebAPI。重构则是因为原先代码有严重的性能问题,而组里并没有能够写好socket通讯的同学。

    WebAPI的编写相对就简单多了,但原先从Server端push消息到Client的功能就需要找到替代的解决方案。所以有了本篇对于SignalR的介绍。

    “ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。”看不懂不能怪我,MSDN上的原话。简单可以理解为SignalR是一个基于WebSocket的库,能够帮助我们避免直接使用socket,而写出一些性能夸张的代码……

    SignalR的基本push流程是这样的,首先Server端有一个Hub类,Hub类中会定义一个方法,该方法会在某个时机被触发,而在该方法内部,会有一个Clients.All.SendAsync之类的操作。然后通过该SendAsync方法,来将消息内容传递给事先定义好的Client端的方法。

        public class TestCaseHub : Hub
        {
            public async Task SayHello()
            {
                await Clients.All.SendAsync("AreYouOK");
            }
        }

    上述代码中(TestSignalRServer工程的HubsTestCaseHub.cs),TestCaseHub中的SayHello方法执行时,会调用client端的AreYouOK方法。为了简单起见,这个方法没有参数。

    SignalR客户端的结构也很简单,打开TestSignalRClient工程的program.cs文件,仅有的Main方法如下:

            static void Main(string[] args)
            {
                HubConnection connection = new HubConnectionBuilder().WithUrl("https://localhost:44306/TestCaseHub").Build();
                
     connection.On("AreYouOK", () =>
                {
                    Console.WriteLine("Fine, thank you. And you?");
                });
      
                connection.StartAsync();
                Console.WriteLine("Start connect");
                Console.ReadKey();
            }

    首先通过Hub的url build出HubConnection对象。再通过HubConnection的On方法,向Server端注册AreYouOK方法。这个方法会在Server端通过SendAsync来被调用。

    可能有新同学会问Hub的url是什么,这是因为SignalR是基于ASP.Net Core工程的,所以TestSignalRServer工程实际是一个Visual Studio里创建的Web Application,我们打开Startup类,可以看到注册了SignalR的service和TestCaseHub类的route映射。(TestSignalRServer的代码是.NET Core 2.2的,后面我们还会创建.NET Core 3.1的,通过WebApi调用触发的SignalR通知,代码会有细微的差别)

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddSignalR();
            }
      
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
      
                app.UseFileServer();
                app.UseSignalR(routes =>
                {
                    routes.MapHub<TestCaseHub>("/testcasehub");
                });
            }

    在TestSignalRServer这个Web Application中,最终是通过html页面上的button,执行javascript来触发SayHello方法,最终将通知发送到Console Client。而我们实际的需求,是需要一个WebApi来触发SignalR通知。还记得开头提到的WinForms程序吗?由WinForms程序调用WebApi,传递要push给Console Client的参数,再通过包含SignalR Hub的WebApi完成push。

    首先我们创建一个空的ASP.NET Core Web Application。模板类型选择API。

    默认的API模板会包含一个WeatherForecastController,此时按下F5运行,可以测试下环境是否配置正确。

    接下来我们创建NotificationHub。啥也不用写,空的就行了。

        public class NotificationHub: Hub
        {
        }

    然后照着WeatherForecastController抄袭一个NotificationController。NotificatoinHub空着的原因在于我们将SendAsync写在这里了。具体可以参考“Send messages from outside a hub”。ASP.NET Core可以通过自带的依赖注入框架,在Controller里获取IHubContext对象。

        [Route("api/[controller]")]
        [ApiController]
        public class NotificationController : ControllerBase
        {
            private readonly IHubContext<NotificationHub> _hubContext;
      
            public NotificationController(IHubContext<NotificationHub> hubContext)
            {
                _hubContext = hubContext;
            }
      
            [HttpGet]
            public async Task<IActionResult> Notify()
            {
                await _hubContext.Clients.All.SendAsync("Notify", $"It's time: {DateTime.Now}");
                return Ok();
            }
        }

    在Startup里添加上对SignalR的service使用和endpoint设置,Server端的编写就结束了。

          public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
                services.AddSignalR();
            }
      
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
      
                app.UseHttpsRedirection();
      
                app.UseRouting();
      
                app.UseAuthorization();
      
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                    endpoints.MapHub<NotificationHub>("/notificationHub");
                });
            }

    Client的代码和之前.NET Core 2.2的例子基本没有区别,唯一不同这次带了一个string参数。强类型的参数SignalR也是支持的,会自动完成序列化和反序列化的操作。

                var connection = new HubConnectionBuilder()
                    .WithUrl("https://localhost:44354/NotificationHub")
                    .Build();
      
                await connection.StartAsync();
      
                connection.On<string>("Notify", (a) =>
                {
                    Console.WriteLine($"Notify: {a}");
                });

    如果发现找不到HubConnectionBuilder,记得去NuGet安装Microsoft.AspNetCore.SignalR.Client。

    将包含NotificationConroller的Web Applicatin和Console Client分别启动后。我们只需要访问https://localhost:xxxx/api/notification这个地址,即可触发SignalR通知。从下图看这是一个简单的报时通知。

    本篇介绍了如何创建ASP.NET Core的WebApi,实现从Server端push消息到Client。同时将触发通知的操作放到WebApi的Controller里,从而避免了html和javascript的编写,缓解了传统桌面开发人员的不适,延长了部分寿命。

    Sample工程:

    SignalRTest基于.NET Core 2.2,在抄袭了官方sample的基础上,实现点击html页面的button推送小文件给Client的功能。

    https://github.com/manupstairs/SignalRTest

    SignalRTest1一看名字就很随性,基于.NET Core 3.1,写成WebApi的形式,作为专门的Notification Service。

    https://github.com/manupstairs/SignalRTest1

  • 相关阅读:
    OpenCV学习(10) 图像的腐蚀与膨胀(1)
    OpenCV学习(6) 文件和Mat之间的数据交换
    OpenCV学习(5) Mat的基本操作(2)
    OpenCV学习(4) Mat的基本操作(1)
    OpenCV学习(3) OpenCV框架
    OpenCV学习(2) OpenCV的配置
    OpenCV学习(1) OpenCV的安装
    Android触控屏幕Gesture(GestureDetector和SimpleOnGestureListener的使用教程) 分类:Androidandroid实例
    转载 C++实现的委托机制
    C++如何禁止掉对象的复制操作
  • 原文地址:https://www.cnblogs.com/manupstairs/p/12532001.html
Copyright © 2020-2023  润新知