什么是后台主机

在之前的 Asp.NETCore 轻松学系列中,曾经介绍过一个轻量级服务主机 IHostedService ,利用 IHostedService 可以轻松的实现一个系统级别的后台服务,该服务跟随系统启动和停止;同时,其使用异步加载和兼容注入的特性,可以很好的实现业务的扩展和隔离。

IHostedService 有一个默认的实现基类 Microsoft.Extensions.Hosting.BackgroundService,我们仅需要继承 BackgroundService 即可实现后台主机。

本文主要目的在于实现一个后台心跳广播包,所有连接到 SignalR 的客户端,通过订阅心跳包广播频道,能够自动收到服务器发送的心跳广播

广播协议定义

    public interface IHeartbeat
{
Task HeartbeatAsync(int data);
}

上面定义 了一个接口 IHeartbeat,该接口有一个异步的方法 HeartbeatAsync,主要就是心跳的定义,先不管它怎么使用,我们继续往下

定义一个泛型的 Hub

    public class WeChatHub : Hub<IHeartbeat>
{
public void Send(ChatMessage body)
{
Clients.All.RecvAsync(body);
} public override Task OnConnectedAsync()
{
Console.WriteLine("游客[{0}]进入了聊天室", this.Context.ConnectionId);
return base.OnConnectedAsync();
} public override Task OnDisconnectedAsync(Exception exception)
{
Console.WriteLine("游客[{0}]离开了聊天室", this.Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
}

上面定义了一个SignalR通信管理对象 WeChatHub ,其继承字泛型的 Hub,其中,泛型类型指定为 IHeartbeat 接口,这里的泛型即表示 SignalR 的客户端,其代表一种通信协议包,SignalR 的客户端(各种类型的)如果希望收到 IHeartbeat 定义的消息(方法实现),必须侦听 IHeartbeat 的定义(方法名称和参数)

上面的这段话比较绕口,其实我也觉得不太好理解,简单来说就是客户端要侦听一个和 SignalR 服务端定义的相同的频道,才可以收到广播。

定义后台服务主机

在定义好 SignalR 的通信协议后,接下来要做的就是实现一个后台服务主机,也就是 IHostedService 的实现。根据 Asp.Net Core 轻松学-基于微服务的后台任务调度管理器 中的提示,我们不需要实现这个接口,只需要继承 Microsoft.Extensions.Hosting.BackgroundService 即可

实现代码
    public class WeChatHubWorker : BackgroundService
{
private readonly IHubContext<WeChatHub, IHeartbeat> heartbeat;
public WeChatHubWorker(IHubContext<WeChatHub, IHeartbeat> heartbeat)
{
this.heartbeat = heartbeat;
} protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await this.heartbeat.Clients.All.HeartbeatAsync(0);
await Task.Delay(3000);
Console.WriteLine("heartbeat");
}
}
}

上面的代码比较简单,首先定义了 IHubContext<WeChatHub, IHeartbeat> 对象 heartbeat,然后在构造函数中通过注入的方式将其实例化,紧接着在 ExecuteAsync(CancellationToken stoppingToken) 方法中,执行了一个无限循环的操作,每 3000 毫秒给所有 SignalR 客户端发送一个内容为 0 的心跳包。

服务注入

实现了后台主机后,需要将其注入到 Asp.NETCore 的管道中

// 添加服务主机随主机启动
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddHostedService<WeChatHubWorker>();
...
} // 配置 SignalR 侦听的 Uri 地址
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSignalR(routes =>
{
routes.MapHub<WeChatHub>("/wechatHub");
});
...
}

通过服务注入,我们就完成了服务端的实现,下面看看 JavaScript 的实现。

JavaScript 客户端的实现

var connection = new signalR.HubConnectionBuilder()
.withUrl("/wechatHub")
.build(); connection.on("RecvAsync", function (data) {
var li = document.createElement("li");
li = $(li).text(data.userName + ":" + data.content);
$("#msgList").append(li);
}); connection.on("HeartbeatAsync", (data) => {
console.log(data);
}); connection.start()
.then(function () {
console.log("客户端已连接");
}).catch(function (err) {
console.log(err);
});

上面的代码,如果有看过前两章的同学,应该是非常熟悉的,这里就不多解释了;但是,由于本次 SignalR 服务端的 Hub 实现不太一样,所以,这里还是要解释一下。

上面的代码分别侦听了两个通道 connection.on("RecvAsync",...) 和 connection.on("HeartbeatAsync",...) ,这两个通道对应服务端的 IHeartbeat 的定义的成员名称,然后在 Callback 中的参数,也需要和 IHeartbeat 定义的一样,保证可以完整接收服务端推送的消息。

  • RecvAsync 通道用来接收和发送客户端的聊天消息(主动/被动)
  • HeartbeatAsync 通道用来接收来自服务端推送的心跳广播(被动)

运行演示

运行服务端,分别打开两个客户端,同时观察服务端和客户端的心跳输出

红圈处就是心跳广播的内容:0。

使用两个客户端分别发送聊天消息

红圈处就是聊天消息。

扩展

如果需要开通多个通道的话怎么办呢,聪明的你一定想到了,就是增加 IHeartbeat 的定义,然后在客户端订阅该频道即可。

示例代码下载

https://github.com/lianggx/Examples/tree/master/SignalR/Ron.SignalRLesson3

在后台主机中托管SignalR服务并广播心跳包的更多相关文章

  1. Azure开发者任务之七:在Azure托管服务中托管WCF服务角色

    在一个托管服务中托管一个WCF服务角色和托管一个ASP.Net Web Role基本类似. 在上一篇文章中,我们学习了如何使用WCF Service Web Role. 在本文中,我会对上一篇文章进行 ...

  2. 腾讯云 TKE Everywhere 特性发布,用户可在自有基础设施中托管 K8s 服务

    作者 孔令飞,腾讯云资深工程师,拥有大规模 Kubernetes 集群.微服务的研发和架构经验,目前专注于云原生混合云领域的基础架构开发. 朱翔,腾讯云容器服务高级产品经理,目前负责云原生混合云产品方 ...

  3. 创建自托管的SignalR服务端

    微软官方例子地址:http://www.asp.net/signalr/overview/deployment/tutorial-signalr-self-host 1.说明: SignalR服务端可 ...

  4. SignalR入门之多平台SignalR服务端

    之前创建SignalR服务端是基于Web应用程序而言的.那么能不能把SignalR服务端做成控制台应用程序.Winform或windows服务呢? 答案是肯定的. 之前尽管看起来好像是IIS和ASP. ...

  5. 一、在 ASP.NET Core 中使用 SignalR

    一.介绍 SignalR 是一个用于实现实时网站的 Microsoft .NET 库.它使用多种技术来实现服务器与客户端间的双向通信,服务器可以随时将消息推送到连接的客户端. https://docs ...

  6. Signalr 实现心跳包

    项目分析: 一个实时的IM坐席系统,客户端和坐席使用IM通信,客户端使用android和ios的app,坐席使用web. web端可以保留自己的登录状态,但为防止意外情况的发生(如浏览器异常关闭,断网 ...

  7. IIS 中托管基于TCP绑定的WCF服务

    IIS 中托管基于TCP绑定的WCF服务 一.创建一个基于TCP绑定的WCF服务 1.创建一个的简单的服务具体代码如下 服务契约定义 namespace SimpleService { // 注意: ...

  8. windows 服务中托管asp.net core

    在windows 服务中托管asp.net core SDK 2.1.300 官方示例 1.添加运行标识符 xml <PropertyGroup> <TargetFramework& ...

  9. 三十、【C#.Net开发框架】WCFHosting服务主机的利用WCF服务通讯和实现思路

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...

随机推荐

  1. C++开发中BYTE类型数组转为对应的字符串

    下午密码键盘返回了一个校验码,是BYTE类型数组,给上层应用返回最好是字符串方式,怎样原样的将BYTE数组转为string串呢?不多说,开动脑筋上手干!!! BYTE格式的数组bt{08,D7,B4, ...

  2. linux下 mysql数据库的备份和还原sql

    1.备份 [root@CentOS ~]# mysqldump -u root -p mysql > ~/mysql.sql #把数据库mysql备份到家目录下命名为mysql.sql Ente ...

  3. JS跨域:1.解决方案之-SpringMVC拦截器

    一 拦截器代码 package com.wiimedia.controller; import java.util.List; import javax.servlet.http.HttpServle ...

  4. C++ 文件流的详解

    部分内容转载:http://blog.csdn.net/kingstar158/article/details/6859379 感谢追求执着,原本想自己写,却发现了这么明白的文章. C++文件流操作是 ...

  5. 1 Numpy-科学计算

    在Python中,使用list可以保存一组值,可以作为数组使用,但是比较浪费内存和时间.类似的array模块,不支持多维,也没有各种函数运算,因此也极其不方便. 为解决这一问题,Python提供了Nu ...

  6. DDD实战进阶第一波(十):开发一般业务的大健康行业直销系统(实现经销商登录仓储与逻辑)

    上一篇文章主要讲了经销商注册的仓储和领域逻辑的实现,我们先把应用服务协调完成经销商注册这部分暂停一下,后面文章统一讲. 这篇文章主要讲讲经销商登录的仓储和相关逻辑的实现. 在现代应用程序前后端分离的实 ...

  7. C语言 > 构造素数表

    #include <stdio.h> #define NUMBER 1000 int main(){ int isPrime[NUMBER]; ; i < NUMBER; i++){ ...

  8. Java中判断是否为空的方法

    1.判断字符串或者对象是否为空 首先来看一下工具StringUtils的判断方法: 一种是org.apache.commons.lang3包下的: 另一种是org.springframework.ut ...

  9. IOC 的理解与解释

    IOC 是什么? Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不 ...

  10. Maven install命令理解

    每一个构建都需要唯一的坐标来标识位置,我们根据坐标位置就能够下载构建至本地仓库.那么如果我们是内部项目,自定义的构建并不公开至网络上,项目成员又想依赖他怎么办呢?想想maven找寻构建的步骤. 先找寻 ...