标题起得有点厉害, 汉字夹杂着 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 工程的 Hubs\TestCaseHub.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
来源: https://www.cnblogs.com/manupstairs/p/12532001.html