发现 ASP.NET Core SignalR

ASP.NET SignalR 是几年前推出的工具,可供 ASP.NET 开发人员使用,以向应用程序添加实时功能。只要基于 ASP.NET 的应用程序必须接收来自服务器(从监视系统到游戏)的频繁异步更新,就属于典型的库用例。这些年来,我还使用它来刷新 CQRS 体系结构方案中的 UI,以及在 socialware 应用程序中实现与 Facebook 类似的通知系统。从更具技术性的角度来看,SignalR 是抽象层,生成依据为一部分可以在完全兼容的客户端和服务器之间建立实时连接的传输机制。客户端通常为 Web 浏览器,服务器通常为 Web 服务器,但两者都不仅限于此。

ASP.NET SignalR 属于 ASP.NET Core 2.1。虽然库的总体编程模型与经典 ASP.NET 的编程模型类似,但库本身实际上已经完全重写。尽管如此,只要开发人员适应各方面的变化,应该就可以快速熟练掌握新方案。本文将介绍如何在规范 Web 应用程序中使用新库来监视可能会很漫长的远程任务。

设置环境

可能需要以下多个 NuGet 包,才能使用库:Microsoft.AspNetCore.SignalR 和 Microsoft.AspNetCore.SignalR.Client。前一个包提供核心功能;后一个包是 .NET 客户端,且只有在生成 .NET 客户端应用程序时才需要。此示例将通过 Web 客户端来使用库,因此改为需要 SignalR NPM 包。本文稍后将详细介绍这一点。请注意,在基于 MVC 应用程序模型的 Web 应用程序的上下文中使用 SignalR 并不是一项强制性要求。可以直接通过 ASP.NET Core 控制台应用程序使用 SignalR 库服务,还可以在控制台应用程序中托管 SignalR 的服务器部分。

应用程序的启动类需要包含一些特定代码,这一点不足为奇。具体而言,将把 SignalR 服务添加到系统服务集合中,并将它配置为可供实际使用。图 1 展示了使用 SignalR 的启动类的典型状态。

图 1:SignalR ASP.NET Core 应用程序的启动类

public class Startup
{public void ConfigureServices(IServiceCollection services){services.AddMvc();services.AddSignalR();}public void Configure(IApplicationBuilder app){app.UseStaticFiles();app.UseDeveloperExceptionPage();// SignalR    app.UseSignalR(routes =>{routes.MapHub<UpdaterHub>("/updaterDemo");routes.MapHub<ProgressHub>("/progressDemo");});app.UseMvcWithDefaultRoute();}
}

SignalR 服务配置包括一个或多个服务器路由的定义,这些路由绑定到服务器端环境中的一个或多个终结点。MapHub<T> 方法将请求 URL 中的指定名称链接到 Hub 类的实例中。Hub 类既是实现 SignalR 协议的核心所在,也是处理客户端调用的位置所在。为服务器端打算接受和处理的每组逻辑相关调用创建 Hub。SignalR 对话由双方之间交换的消息组成,一方对另一方调用方法的结果可能是没有响应,可能是收到一个或多个响应,也可能是仅收到错误通知。任何 ASP.NET Core SignalR 服务器实现都会公开一个或多个 Hub。在图 1 中,有两个 Hub 类(UpdaterHub 和 ProgressHub)绑定到唯一字符串,这些字符串在内部用于生成实际调用的 URL 目标。

Hub 类

SignalR 应用程序中的 Hub 类是普通的简单类,继承自 Hub 基类。此基类仅用于免去开发人员一次又一次编写相同样本代码的麻烦。基类只提供某基础结构,而不提供预定义行为。具体而言,它定义了图 2 中的成员。

图 2:Hub 基类的成员

成员说明
客户端公开当前由 Hub 托管的客户端列表的属性。
上下文公开当前调用方上下文的属性,包括连接 ID 和用户声明(若有)等信息。
公开各客户端子集的属性,这些客户端可能已经以编程方式定义为完整客户端列表中的组。组通常创建用于向选定受众广播特定消息。
OnConnectedAsync每当有新客户端连接到 Hub 时调用的虚拟方法。
OnDisconnectedAsync每当有新客户端与 Hub 断开连接时调用的虚拟方法。


最简单的 Hub 类如下所示:

public class ProgressHub : Hub
{
}

有趣的是,如果在 ASP.NET Core MVC 应用程序上下文中从控制器方法内使用它,就会直接采用 Hub 形式。几乎所有的 ASP.NET Core SignalR 示例(包括聊天示例)往往都会在客户端和 Hub 之间进行直接绑定和双向绑定,无需控制器提供任何形式调解。在这种情况下,Hub 采用的形式将会更有形一点:

public class SampleChat : Hub
{     // Invoked from outside the hub  public void Say(string message){// Invoke method on listening client(s)    return Clients.All.InvokeAsync("Said", message);}
}

与数十篇博客文章中换汤不换药的规范 SignalR 聊天示例不同,本文中的示例其实并没有在客户端和服务器之间建立双向对话。虽然连接是从客户端建立的,但在此之后,客户端就不会发送其他任何请求。相反,服务器会监视任务进度,并在适当时将数据推送回客户端。也就是说,只有当用例要求客户端直接调用公共方法时,Hub 类才必须像上面的代码一样使用这些方法。如果有点复杂难懂,下面的示例足以阐明这一点。

监视远程任务

它的具体情形是这样的:ASP.NET Core 应用程序为用户提供了某 HTML 接口,以方便用户触发可能会很漫长的远程任务(如创建报告)。因此,作为开发人员,需要显示进度栏,以持续反馈进度(见图 3)。

640?wx_fmt=png

图 3:使用 SignalR 监视远程任务的进度

可以猜到,在此示例中,客户端和服务器都在同一个 ASP.NET Core 项目的上下文中设置 SignalR 实时会话。在此开发阶段中,MVC 项目功能齐全,它使用图 1 中的启动代码进行了扩展。接下来,将设置客户端框架。需要在与 SignalR 终结点交互的所有 Razor(或纯 HTML)视图中完成此设置。

若要在 Web 浏览器中与 SignalR 终结点进行通信,首先要添加对 SignalR JavaScript 客户端库的引用:

<script src="~/scripts/signalr.min.js">
</script>

可以通过多种方式获取此 JavaScript 文件。最值得推荐的方法是,使用几乎所有开发计算机上都有的 Node.js 包管理器 (NPM) 工具(特别是在 Visual Studio 2017 版本推出后)。通过 NPM,查找并安装名为 @aspnet/signalr 的 ASP.NET Core SignalR 客户端。它会将许多 JavaScript 文件复制到磁盘,但其中只有一个文件才是大多数情况唯一需要的。不管怎样,这就是简单地链接 JavaScript 文件,还可以通过其他许多方式来获取此文件,包括从旧版 ASP.NET Core SignalR 项目中复制它。然而,NPM 是团队提供的唯一受支持的脚本获取方式。另请注意,ASP.NET Core SignalR 不再依赖 jQuery。

在客户端应用程序中,还需要另一段更具体的 JavaScript 代码。特别是,需要如下代码:

var progressConnection =new signalR.HubConnection("/progressDemo");
progressConnection.start();

与 SignalR Hub 建立的连接与指定路径匹配。更确切地说,以参数形式传递到 HubConnection 的名称,应该是映射到启动类中路由的名称之一。在内部,HubConnection 对象准备了串联当前服务器 URL 和给定名称生成的 URL 字符串。只有当此 URL 与已配置的路由之一匹配时,才会处理它。另请注意,如果客户端和服务器不是相同的 Web 应用程序,那么必须向 HubConnection 传递托管 SignalR Hub 的 ASP.NET Core 应用程序的完整 URL,外加 Hub名称。

然后,必须通过 start 方法打开 JavaScript Hub 连接对象。可以使用 JavaScript 承诺(特别是 then 方法)或 TypeScript 中的 async/await 执行后续操作(如初始化某用户界面)。SignalR 连接由字符串 ID 唯一标识。

请务必注意,如果传输连接或服务器失败,ASP.NET Core SignalR 就不再支持自动重新连接。在旧版中,如果发生服务器故障,客户端会尝试根据计划算法重新建立连接。如果成功,它会使用相同的 ID 重新打开连接。在 SignalR Core 中,如果连接中断,客户端只能通过 start 方法再次启动连接,这就会生成连接 ID 不同的其他连接实例。

客户端回调 API

需要的另一段基本 JavaScript 代码是,Hub 回调的 JavaScript,用于刷新接口并在客户端上反映服务器上的进度。虽然这段代码在 ASP.NET Core SignalR 中的编写方式与旧版中的略有不同,但意向是完全相同的。此示例中有以下三个方法能够从服务器回调:initProgressBar、updateProgressBar 和 clearProgressBar。不用说,可以使用任意名称和签名。以下是实现示例:

progressConnection.on("initProgressBar", () => {setProgress(0);$("#notification").show();
});
progressConnection.on("updateProgressBar", (perc) => {setProgress(perc);
});
progressConnection.on("clearProgressBar", () => {setProgress(100);$("#notification").hide();
});

例如,如果从服务器回调 initProgressBar 方法,帮助程序 setProgress JavaScript 函数就会配置并显示进度栏(此演示使用的是启动进度栏组件)。请注意,代码中使用了 jQuery 库,但仅用于更新 UI。如前所述,客户端 SignalR Core 库不再是 jQuery 插件。也就是说,如果 UI 是基于 Angular 等,可能根本无需使用 jQuery。

服务器端事件

缺少的解决方案部分是,决定何时调用客户端函数。主要有以下两种方案。一种是在客户端通过 Web API 或控制器终结点调用服务器操作时调用。另一种是在客户端直接调用 Hub 时调用。最后,只需决定在哪里为回调客户端的任务编写代码。

在规范聊天示例中,这一切都发生在 Hub 中:执行所需的全部逻辑,并将消息分派给相应连接。监视远程任务是另一回事。它假设后台正在运行某业务流程,以通过某种方式通知进度。从技术角度来讲,可能会在 Hub 中编码此流程,并从中建立与客户端 UI 之间的对话。也可以让控制器 (API) 触发此流程,Hub 仅用于将事件传递给客户端。比此示例更为实际的做法是,在低于控制器级别的层中编码此流程。

总而言之,可以定义 Hub 类,并随时可将它用于决定何时以及是否调用客户端函数。有趣的地方在于,需要什么才能将 Hub 实例注入控制器或其他业务类。此演示在控制器中注入 Hub,但也会对其他更深级别的类执行完全相同的操作。示例 TaskController 是通过 JavaScript 直接从客户端调用,以触发进度栏将显示其进度的远程任务:

public class TaskController : Controller
{private readonly IHubContext<ProgressHub> _progressHubContext;public TaskController(IHubContext<ProgressHub> progressHubContext){_progressHubContext = progressHubContext;}public IActionResult Lengthy(){// Perform the task and call back  }
}

通过 IHubContext<THub> 接口在控制器或其他任何类中注入 Hub。IHubContext 接口封装 Hub 实例,但无法直接访问它。从中可以将消息分派回 UI,但无法访问连接 ID(举个例子)。假设远程任务是在 Lengthy 方法中执行,并需要在其中更新客户端进度栏:

progressHubContext.Clients.Client(connId).InvokeAsync("updateProgressBar", 45);

连接 ID 可以从 Hub 类中进行检索,但无法像此示例一样从通用 Hub 上下文中进行检索。因此,最简单的方法是,让客户端方法在启动远程任务时就传递连接字符串:

public void Lengthy([Bind(Prefix="id")] string connId) { … }

最后,控制器类接收 SignalR 连接 ID,注入有 Hub 上下文,并使用通过非类型化通用 API 调用的上下文方法(InvokeAsync 方法)执行操作。这样一来,Hub 类就无需包含任何方法!如果觉得这很奇怪,请参阅 bit.ly/2DWd8SV 中的代码。

总结

本文介绍了如何在 Web 应用程序上下文中使用 ASP.NET Core SignalR 监视远程任务。Hub 几乎是空的,因为所有通知逻辑都被内置到控制器中,并使用通过 DI 注入的 Hub 上下文进行编排。这只是 ASP.NET Core SignalR 漫长旅程的起点。接下来,我将深入研究基础结构,并探索类型化 Hub。


Dino Esposito 在他 25 年的职业生涯中撰写了超过 20 本书籍和 1,000 篇文章。Esposito 不仅是舞台剧《事业中断》的作者,还是 BaxEnergy 的数字策略分析师,正忙于编写有助于建设环保世界的软件。可以在 Twitter 上关注他 (@despos)。

原文:https://msdn.microsoft.com/zh-cn/magazine/mt846469


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3、mybatis的全局配置文件mybatis-config.xml

对于初学者&#xff0c;如果进行mybatis的学习呢&#xff1f;我总结了几点&#xff0c;会慢慢的更新出来。首先大家需要了解mybatis是什么、用mybatis来做什么、为什么要用mybatis、有什么优缺点&#xff1b;当知道了为什么的时候就开始了解如何用的问题&#xff0c;如何使用my…

谈谈Circuit Breaker在.NET Core中的简单应用

前言由于微服务的盛行&#xff0c;不少公司都将原来细粒度比较大的服务拆分成多个小的服务&#xff0c;让每个小服务做好自己的事即可。经过拆分之后&#xff0c;就避免不了服务之间的相互调用问题&#xff01;如果调用没有处理好&#xff0c;就有可能造成整个系统的瘫痪&#…

4、mybatis通过配置类Configuration 实现初始化

对于初学者&#xff0c;如果进行mybatis的学习呢&#xff1f;我总结了几点&#xff0c;会慢慢的更新出来。首先大家需要了解mybatis是什么、用mybatis来做什么、为什么要用mybatis、有什么优缺点&#xff1b;当知道了为什么的时候就开始了解如何用的问题&#xff0c;如何使用my…

.NET Core 在中国的现状调研

.NET Core 即将发布2.1版本&#xff0c;在过去的3年多时间里发生了很大的变化&#xff0c;具体可以看看 .NET Core&#xff1a;新的快速开发平台&#xff0c;现在向大家征求意见&#xff0c;调研.NET Core的使用情况。希望大家认真填写&#xff0c;促进.NET Core的发展 。本次调…

5、mybatis中的映射器

目录 1、映射器是什么&#xff1f; 2、自定义sql和使用的分类 2、1 根据定义sql的两种方式分类 2、2 根据使用方式分类 mybatis在实际使用时&#xff0c;最主要的还是映射器。这一篇大体介绍一下映射器&#xff0c;但是有个问题&#xff0c;这篇文章全是我自己对应映射器的…

codeforces 884E Binary Matrix 并查集,滚动数组

E. Binary Matrixtime limit per test3 secondsmemory limit per test16 megabytesinputstandard inputoutputstandard outputYou are given a matrix of size n  m. Each element of the matrix is either 1 or 0. You have to determine the number of connected component…

使用ILSpy探索C#7.0新增功能点

第一部分&#xff1a;C&#xff03;是一种通用的&#xff0c;类型安全的&#xff0c;面向对象的编程语言。有如下特点&#xff1a;&#xff08;1&#xff09;面向对象&#xff1a;c# 是面向对象的范例的一个丰富实现, 它包括封装、继承和多态性。C#面向对象的行为包括&#xff…

【动态规划】叠放箱子问题(ssl 1640)

叠放箱子问题叠放箱子问题叠放箱子问题 Description 某港口有一批集装箱&#xff0c;将其编号&#xff0c;分别为1至N。每一个箱子的外型尺寸都是一样的&#xff0c;现在要将其中某些集装箱叠放起来&#xff0c;集装箱叠放的规则如下&#xff1a; 1)每个集装箱上最多只能直接…

Ubuntu 16.04+.Net Core+Docker+Nginx安装部署

前言最近公司的项目打算移植到.Net Core平台&#xff0c;所以调研了一下.Net Core在Linux下的安装部署。本篇文章会一步步的描述从安装到配置到部署的全部过程。在文章的结构和内容里&#xff0c;笔者借鉴了很多其他博文的内容&#xff0c;但感觉其他博文中都只是实现了一部分或…

玩Docker只要浏览器就够了,PWD是个神奇的网站

本文是d4d系列的第9篇&#xff0c;在这一篇中给大家介绍一个学习Docker最为快捷高效的方式&#xff0c;你不需要自己搭建环境&#xff0c;也不用担心把自己的开发环境搞乱&#xff0c;你需要的只是一个浏览器&#xff0c;就可以立即开始学习Docker的常用命令&#xff1b;你甚至…

[系统安全]使用OD编写连连看外挂

文档下载地址&#xff1a;https://pan.baidu.com/s/1hrzzerq

2018 .NET开发者调查报告: .NET Core 是怎么样的状态

4月28日&#xff0c;在公众号里发起《.NET Core 使用调查》&#xff0c;该调查为期一周&#xff0c;有近3300名开发者参与&#xff0c;统计下结果供你的决策参考。已经使用.net core 的人数只有44%&#xff0c;计划使用.net core 比例达到48%&#xff0c; 没有计划去使用.net …

软件质量保证划重点期末复习总结

软件质量保证复习总结大纲及问题 Module1 《软件工程实践》 1、软件工程实践通过解决问题的根源来指导软件开发。 2、软件工程实践之间相辅相成。 3、过程指导一个团队在什么时候做什么以及如何做。 4、软件工程过程为实现软件工程实践提供了上下文和支持。 Module2 《软件…

Microsoft Build 2018 直播来啦!

一年一度的Microsoft Build大会又来啦&#xff01;Microsoft Build是微软面向全球开发者、合作伙伴以及消费者介绍其重要产品在未来一年内发展方向的技术盛会。而今年的Microsoft Build 2018大会是微软巨大蜕变、最彻底组织变革后的第一次前沿技术大会。更多了解&#xff0c;请…

【动态规划】矩阵链相乘 (ssl 1596)/能量项链 (ssl 2006)

矩阵链相乘{\color{Cyan} 矩阵链相乘 }矩阵链相乘 Description Input n表示矩阵的个数(<100) n1个数,表示矩阵(<100) Output 最小的乘法次数 Sample Input 5 5 10 4 6 10 2 Sample Output 348 题目大意&#xff1a; 有n个矩阵&#xff0c;输入n1个数&#x…

10、mybatis中缓存的使用

对于初学者&#xff0c;如何进行mybatis的学习呢&#xff1f;我总结了几点&#xff0c;会慢慢的更新出来。首先大家需要了解mybatis是什么、用mybatis来做什么、为什么要用mybatis、有什么优缺点&#xff1b;当知道了为什么的时候就开始了解如何用的问题&#xff0c;如何使用my…

C#编译器优化那点事

使用C#编写程序&#xff0c;给最终用户的程序&#xff0c;是需要使用release配置的&#xff0c;而release配置和debug配置&#xff0c;有一个关键区别&#xff0c;就是release的编译器优化默认是启用的。优化代码开关即optimize开关&#xff0c;和debug开关一起&#xff0c;有以…

如何在Visual Studio 2017中使用C# 7+语法

前言之前不知看过哪位前辈的博文有点印象C# 7控制台开始支持执行异步方法&#xff0c;然后闲来无事&#xff0c;搞着&#xff0c;搞着没搞出来&#xff0c;然后就写了这篇博文&#xff0c;不喜勿喷&#xff0c;或许对您有帮助。在Visual Studio 2017配置支持C# 7语法心想都VS20…

11、mybatis的功能架构分析

1、Mybatis功能架构 1&#xff09;API接口层&#xff1a;提供给外部使用的接口API&#xff0c;开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。 2&#xff09;数据处理层&#xff1a;负责具体的SQL查找、SQL解析、SQL执…

【动态规划】方格取数 (ssl 1010)

方格取数方格取数方格取数 Description 设有N*N的方格图(N<10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示&#xff08;见样例&#xff09;&#xff1a; 某人从图的左上角的A 点出发&#xff0c;可以向下行走&#xff0c;也可以向右走&#…