标题起得有点厉害,汉字夹杂着E文,不符合教育部公布的“向社会推荐使用的外语词中文译名”规范。不过他管不着我。写本篇的原由,是重构一个现有的WinForms程序,将Server端的部分逻辑从raw socket通信的方式,改成调用WebAPI。重构则是由于原先代码有严重的性能问题,而组里并无可以写好socket通信的同窗。javascript
WebAPI的编写相对就简单多了,但原先从Server端push消息到Client的功能就须要找到替代的解决方案。因此有了本篇对于SignalR的介绍。html
“ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码可以即时将内容推送到客户端。”看不懂不能怪我,MSDN上的原话。简单能够理解为SignalR是一个基于WebSocket的库,可以帮助咱们避免直接使用socket,而写出一些性能夸张的代码……java
SignalR的基本push流程是这样的,首先Server端有一个Hub类,Hub类中会定义一个方法,该方法会在某个时机被触发,而在该方法内部,会有一个Clients.All.SendAsync之类的操做。而后经过该SendAsync方法,来将消息内容传递给事先定义好的Client端的方法。git
public class TestCaseHub : Hub { public async Task SayHello() { await Clients.All.SendAsync("AreYouOK"); } }
上述代码中(TestSignalRServer工程的Hubs\TestCaseHub.cs),TestCaseHub中的SayHello方法执行时,会调用client端的AreYouOK方法。为了简单起见,这个方法没有参数。github
SignalR客户端的结构也很简单,打开TestSignalRClient工程的program.cs文件,仅有的Main方法以下:api
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通知,代码会有细微的差异)app
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。socket
默认的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。