标题起得有点厉害,汉字夹杂着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

.NET Core学习笔记(5)——WebAPI从Server端push消息到Client的更多相关文章

  1. .NET CORE学习笔记系列(2)——依赖注入[7]: .NET Core DI框架[服务注册]

    原文https://www.cnblogs.com/artech/p/net-core-di-07.html 包含服务注册信息的IServiceCollection对象最终被用来创建作为DI容器的IS ...

  2. .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]

    原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...

  3. .NET CORE学习笔记系列(2)——依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在上篇中我们介绍了Cat的基本编程模式,接下来我们就来聊聊Cat的 ...

  4. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  5. .NET CORE学习笔记系列(2)——依赖注入【3】依赖注入模式

    原文:https://www.cnblogs.com/artech/p/net-core-di-03.html IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架中以实现对流 ...

  6. .NET CORE学习笔记系列(2)——依赖注入【2】基于IoC的设计模式

    原文:https://www.cnblogs.com/artech/p/net-core-di-02.html 正如我们在<控制反转>提到过的,很多人将IoC理解为一种“面向对象的设计模式 ...

  7. .NET CORE学习笔记系列(2)——依赖注入【1】控制反转IOC

    原文:https://www.cnblogs.com/artech/p/net-core-di-01.html 一.流程控制的反转 IoC的全名Inverse of Control,翻译成中文就是“控 ...

  8. .NET Core学习笔记(7)——Exception最佳实践

    1.为什么不要给每个方法都写try catch 为每个方法都编写try catch是错误的做法,理由如下: a.重复嵌套的try catch是无用的,多余的. 这一点非常容易理解,下面的示例代码中,O ...

  9. Netty4.0学习笔记系列之一:Server与Client的通讯

    http://blog.csdn.net/u013252773/article/details/21046697 本文是学习Netty的第一篇文章,主要对Netty的Server和Client间的通讯 ...

随机推荐

  1. ./config\make\make install命令详解

    这些都是典型的使用GNU的AUTOCONF和AUTOMAKE产生的程序的安装步骤 一.基本信息 1../configure 是用来检测你的安装平台的目标特征的.比如它会检测你是不是有CC或GCC,并不 ...

  2. S2SH项目实现分页功能

    javaWEB项目实现分页的方法很多,网上也有很多列子,最近工作中S2SH框架项目中需要一个分页的功能,查看了很多用一下方式实现,功能思路很清晰,觉得是很好的一种实现方法,记录下便多学习. 刚开始得到 ...

  3. 使用fastai完成图像分类

    by Wenqi Sun 1 min read Categories Deep Learning Tags Fastai CNN Application 1. 使用现有数据集进行分类 图像数据为Oxf ...

  4. Docker学习笔记_08使用Rancher pipeline搭建基于容器的CICD

    CICD概述 CI-持续集成(Continuous Integration):频繁地将代码集成到主干的一种开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错 ...

  5. Luogu_2434_[SDOI2005]区间

    题目描述 现给定n个闭区间[ai, bi],1<=i<=n.这些区间的并可以表示为一些不相交的闭区间的并.你的任务就是在这些表示方式中找出包含最少区间的方案.你的输出应该按照区间的升序排列 ...

  6. [转]<版本二>写代码的小女孩

    天冷极了,下着雪,又快黑了.这是一年的最后一天——大年夜.在这又冷又黑的晚上,一个乖巧的小女孩在机房里调试程序.她从家里出来的时候还穿着一件外套,但是有什么用呢?那是一双很大的外套——那么大,不知是哪 ...

  7. JavaScript值类型和引用类型有哪些

    JavaScript值类型和引用类型有哪些 (1)值类型:数值.布尔值.null.undefined. (2)引用类型:对象.数组.函数.

  8. 产品需求说明书PRD模版

    <软件自动化测试开发>出版了 XXX产品需求说明书 [版本号:V+数字]                 编  制: 日  期: 评  审: 日  期: 批  准: 日  期:       ...

  9. 安卓权威编程指南-笔记(第23章 HTTP与后台任务)

    1. 网络连接基本 //通过指定URL获取原始数据,并返回一个字节流数组. public byte[] getUrlBytes(String urlSpec)throws IOException{ / ...

  10. MySQL基础篇(05):逻辑架构图解和InnoDB存储引擎详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.MySQL逻辑架构 1.逻辑架构图 基于下面的逻辑架构图,可以大致熟悉MySQL各个架构组件之间的协同工作关系. 很经典的C/S架构风格, ...