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

就好像这个图:

所以,我们先跟着官方文档,创建一个 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. [Leetcode] Roman to integer 罗马数字转成整数

    Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 t ...

  2. 【NOIP 模拟赛】改造二叉树 最长上升子序列

    biubiu~~~ 这道题我一眼就以为是线段树优化dp并且有了清晰的思路但是发现,我不会线段树区间平移,我以为只是我不会,然而根本就不行........ 正解是把序列排出来然后我们让他们减去他们的下标 ...

  3. [洛谷P2016] 战略游戏 (树形dp)

    战略游戏 题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得 ...

  4. 用实例工厂的方法实例化bean

    在实例化bean时,除了setter,constructor方法外,还有实例工厂方法,和静态工厂方法. 看代码: People类的代码如下: package com.timo.domain; publ ...

  5. tomcat内存配置(二)

    Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对JavaJVM有关内存方面的知识进 ...

  6. background-color和background-image问题

    今天撸码的时候发现需要background-color和background-image 一起用,才开始考虑两个可不可以一起用  查阅多方资料才知道可以写成background:color url() ...

  7. struts学习笔记(四)

    一. 文件的上传: 1). 表单需要注意的 3 点 2). Struts2 的文件上传实际上使用的是 Commons FileUpload 组件, 所以需要导入 commons-fileupload- ...

  8. hive的体系架构及安装

    1,什么是Hive? Hive是能够用类SQL的方式操作HDFS里面数据一个数据仓库的框架,这个类SQL我们称之为HQL(Hive Query Language) 2,什么是数据仓库? 存放数据的地方 ...

  9. 【洛谷 P1070】道路游戏 (DP)

    题目链接 这题还是很好想的,看到\(90%\)的数据点时,我就知道要用\(n^3\)的算法(最后10分就算了吧) 然后,数据水,直接暴力\(n^3\)卡过了. 显然是道DP. 设\(f[i]\)表示第 ...

  10. bzoj 1798 维护序列seq 线段树

    裸的线段树,注意标签下放就行了 多么痛的领悟,一定要开int64 /************************************************************** Pro ...