我一直觉得学习的最好方法就是先让程序能够正常运行,才去学习他的原理,剖析他的细节.

就好像这个图:

所以,我们先跟着官方文档,创建一个 SignalR 应用: https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-2.2&tabs=visual-studio

这个例子一共涉及到下面几个步骤:

  • 自定义中心 ChatHub ;
  • 在启动类 Startup 中启用 SignalR 服务,并添加路由;
  • 编写客户端JS
  • 下载 SignalR 官方JS.

自定义中心 : ChatHub

    public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}

"Hub" 一词,有的地方翻译成"集线器",有的地方翻译成"中心",对于我这种非科班出身的人来说,还是"中心"听起简单点.

对于基类 Hub ,xml 是这样说的 : A base class for a SignalR hub.   SignalR 中心的基类.

这个很简单,看这些名字就知道他们是干嘛用的,具体的描述可以看官方文档.

中心的作用可以这样简单的描述:

通过中心,我们能在服务器的代码中定义客户端可以调用的方法(必须是 public);

通过中心,我们能在客户端的代码中定义服务器可以调用的方法.

上述代码,我们通过继承 Hub ,定义了一个自己的中心 : ChatHub (聊天中心) ,在这个类里面,我们做了下面两件事:

  • 定义了客户端可以调用的方法 : SendMessage(string user, string message)
  • 调用了所有连接上 Hub 的客户端的 ReceiveMessage 方法,并将 user,message 两个字符串作为入参传入该方法.

中心定义好了,肯定需要启用

在启动类 Startup 中启用 SignalR 服务,并添加路由

        public void ConfigureServices(IServiceCollection services)
{
...... //注册 SignalR 服务
services.AddSignalR();
}
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...... //设置 SignalR 中心路由
app.UseSignalR(routes => { routes.MapHub<ChatHub>("/chatHub"); }); app.UseMvc();
}

编写客户端JS

"use strict";//不太明白这句话是什么意思...

//创建一个连接到我们创建的 ChatHub 的 connection.
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); //定义客户端的方法,方法名: ReceiveMessage ,两个入参.
//注意,这个方法就是服务器要调用的方法,服务器和客户端的名字一定要一样.
connection.on("ReceiveMessage", function (user, message) {
var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
var encodedMsg = user + " says " + msg;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
}); //开启连接.
connection.start().catch(function (err) {
return console.error(err.toString());
}); document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value; //调用服务器的 SendMessage 方法,并传入两个入参.这和委托的调用太像了.
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});

上面的 ChatHub 类的 SendAsync 方法在调用客户端的方法时,方法名是直接写的 字符串 : "ReceiveMessage"

官方不推荐这样写,因为不是强类型,可能出现运行时错误,因此建议使用强类型的中心

(顺带附上了一些额外的功能):

    //建议使用下面的强类型方式
//方法二
public interface IChatClient
{
//就算是这种强类型方式,客户端定义的方法名也必须和这个方法名一样,包括签名.
Task ReceiveMessage(string user, string message);
} public class StronglyTypedChatHub : Hub<IChatClient>
{
//[HubMethodName("hello")] 可以改名,如果改了名,前端也要跟着改,别忘了.
public async Task SendMessage(string user, string message)
{
//调用客户端定义的 ReceiveMessage 方法.
//throw new HubException("哈哈,出错了!");//可以向客户端发送异常.只会向当前调用的客户端发送,并且只发送 message ,不会发送堆栈信息.        //Clients.Caller 当前客户端
       //Clients.Others 当前客户端的其他客户端
await Clients.All.ReceiveMessage($"{GetHashCode()}" + user, message);//传递 hashCode 是为了证明,每次调用都是不同的实例.所以官方说不要在"中心"里面存状态.
} //该方法可以在客户端连接上后,执行操作
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
} //同理,当客户端断开连接时执行的操作
public override async Task OnDisconnectedAsync(Exception exception)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnDisconnectedAsync(exception);
}
}

当然,注册路由的代码也得换了 :  app.UseSignalR(routes => { routes.MapHub<StronglyTypedChatHub>("/chatHub"); });

好困,明天继续

2019.1.9

复制一段官方的文档.

SignalR 是什么?

ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。

SignalR 的适用对象:

  • 需要来自服务器的高频率更新的应用。 例如:游戏、社交网络、投票、拍卖、地图和 GPS 应用。
  • 仪表板和监视应用。 示例包括公司仪表板、销售状态即时更新或行程警示。
  • 协作应用。 协作应用的示例包括白板应用和团队会议软件。
  • 需要通知的应用。 社交网络、电子邮件、聊天、游戏、行程警示以及许多其他应用都使用通知。

SignalR 提供了一个用于创建服务器到客户端远程过程调用(RPC)的 API。 RPC 通过服务器端 .NET Core 代码调用客户端上的 JavaScript 函数。

以下是 ASP.NET Core SignalR 的一些功能:

  • 自动管理连接。
  • 同时向所有连接的客户端发送消息。 例如,聊天室。
  • 将消息发送到特定的客户端或客户端组。
  • 扩展以处理增加的流量。

传输

SignalR 支持几种方法用于处理实时通信:

SignalR 会从服务器和客户端支持的功能中自动选择最佳传输方法

中心

SignalR 使用中心在客户端和服务器之间进行通信。

“中心”是一种高级管道,允许客户端和服务器相互调用方法。 SignalR 自动处理跨计算机边界的调度,允许客户端和服务器相互调用方法。 可以将强类型参数传递给方法,从而启用模型绑定。 SignalR 提供两个内置中心协议:基于 JSON 的文本协议和基于 MessagePack 的二进制协议。 与 JSON 相比,MessagePack 创建的消息通常比较小。 旧版浏览器必须支持 XHR 2 才能提供 MessagePack 协议支持。

中心通过发送包含客户端方法的名称和参数的消息来调用客户端代码。 使用配置的协议对作为方法参数发送的对象进行反序列化。 客户端会尝试将方法名称与客户端代码中的方法匹配。 当客户端找到匹配项时,它会调用该方法并将反序列化的参数数据传递给它。

发送中心外的信息

上面讲的例子,客户端和服务器的消息都是在"中心"里面流动.实际上,中心还可以把中心之外的信息发送给客户端.(这句话可能有点绕),看示例就明白了.

新建一个测试控制器, 依然通过依赖注入得到 IHubContext 类的实例, StronglyTypedChatHub 类就是上面例子中的那个自定义的强类型中心.

    [Route("api/[controller]")]
[ApiController]
public class TestController
{
private IHubContext<StronglyTypedChatHub, IChatClient> _context; public TestController(IHubContext<StronglyTypedChatHub, IChatClient> context)
{
_context = context;
} public void Get()
{
_context.Clients.All.ReceiveMessage("admin", "在座的各位都是垃圾!");
}
}

测试效果:

这个是强类型中心的例子,下面是普通中心的例子:

    [Route("api/[controller]")]
[ApiController]
public class TestController
{ //强类型中心
//private IHubContext<StronglyTypedChatHub, IChatClient> _context; //public TestController(IHubContext<StronglyTypedChatHub, IChatClient> context)
//{
// _context = context;
//} //普通中心
private IHubContext<ChatHub> _context; public TestController(IHubContext<ChatHub> context)
{
_context = context;
} public void Get()
{
//这种调用客户端方法的方式,好别扭
_context.Clients.All.SendAsync("ReceiveMessage", "admin", "在座的各位都是垃圾!!!");
}
}

ASP.NET Core 2.2 基础知识(十六) SignalR 概述的更多相关文章

  1. ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述

    为了方便演示,以 .NET Core 控制台应用程序讲解. 我们新建一个控制台应用程序,安装 "Newtonsoft.Json" Nuget 包,然后右键点击该项目,选择" ...

  2. ASP.NET Core 2.2 基础知识(十二) 发送 HTTP 请求

    可以注册 IHttpClientFactory 并将其用于配置和创建应用中的 HttpClient 实例. 这能带来以下好处: 提供一个中心位置,用于命名和配置逻辑 HttpClient 实例. 例如 ...

  3. ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)

    要啥自行车,直接看手表 //返回基元类型 public string Get() { return "hello world"; } //返回复杂类型 public Person ...

  4. ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  5. ASP.NET Core 2.2 基础知识(十五) Swagger

    安装 Nuget 包 注册 Swagger public void ConfigureServices(IServiceCollection services) { services.AddMvc() ...

  6. ASP.NET Core 2.2 基础知识(十三) WebAPI 概述

    我们先创建一个 WebAPI 项目,看看官方给的模板到底有哪些东西 官方给出的模板: [Route("api/[controller]")] [ApiController] pub ...

  7. ASP.NET Core 2.2 基础知识(十一) ASP.NET Core 模块

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  8. ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务

    在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法: StartAsync(CancellationT ...

  9. ASP.NET Core 2.2 基础知识(八) 主机 (未完待续)

    主机负责应用程序启动和生存期管理.共有两个主机 API : 1.Web 主机 : 适用于托管 Web 应用,基于 IWebHostBuilder ; 2.通用主机 : 适用于托管非 Web 应用. 基 ...

随机推荐

  1. ng websocket

    ng使用websocket 1.安装依赖库npm install ws --save 2.安装类型定义文件 npm install @types/ws --save 3.编写服务 import { I ...

  2. Spring中Resource接口的前缀书写格式

    Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");   //这个 ...

  3. 怎么让Intellj Idea 把数据库的表映射成hibernate的domain对象

    步骤如下: 第一步:连接数据源: 点击:idea右边的database.如下图所示: 或者你依次点击:view-->Tool windows--->database 然后你将看在如下点击下 ...

  4. 【洛谷 P1337】[JSOI2004]平衡点 / 吊打XXX (模拟退火)

    题目链接 正解就算了吧,谁叫我理生化 语数外 政史地都菜呢 模拟退火真玄学,不知道发生了什么就跑出答案了,原理就算了吧,能用(pianfen)就好. 当重物平衡时,势能一定是最小的,于是当我随机出一个 ...

  5. bzoj 2749 杂题

    我们可以发现,phi(x)与x相比,相当于x的每个质因子-1后再分解质因数,添加到现有的质因子中,比如质因子13相当于将13变成12,然后分解成2*2*3,再将2的质数+2,3的指数+1,除了质因子2 ...

  6. python学习笔记 异步asyncio

    asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio的编程模型就是一个消息循环.我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要 ...

  7. kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

    第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一 ...

  8. IC卡文件系统的逻辑结构【转】

    转自:http://bbs.ednchina.com/BLOG_ARTICLE_172028.HTM 文件系统是COS的重要模块之一,它负责组织.管理.维护IC卡内存储的所有数据.文件系统的设计和实现 ...

  9. Linux core dump file详解

    Linux core dump file详解 http://www.cnblogs.com/langqi250/archive/2013/03/05/2944931.html

  10. 《Java编程思想》笔记 第十章 内部类

    1.创建内部类对象 创建内部类对象(相当于new内部类对象) 外围类对象.new 内部类( ). 创建内部类对象一种方法是 外围类有一个方法返回内部类对象. 没有外围类对象就不能创建内部类对象,因为内 ...