作者 :帕特里克·弗莱彻
警告
本文档不适用于最新版本的 SignalR。 查看 ASP.NET Core SignalR。
本文介绍 SignalR 是什么,以及它旨在创建的一些解决方案。
问题和评论
请留下有关你喜欢本教程的方式以及我们在页面底部的评论中可以改进的内容的反馈。 如果存在与本教程不直接相关的问题,可以将这些问题发布到 ASP.NET SignalR 论坛 或 StackOverflow.com。
什么是 SignalR?
ASP.NET SignalR 是一个库,面向 ASP.NET 开发人员,简化了向应用程序添加实时 Web 功能的过程。 实时 Web 功能使服务器代码在可用时立即将内容推送到连接的客户端,而不是让服务器等待客户端请求新数据。
SignalR 可用于将任何类型的“实时”Web 功能添加到 ASP.NET 应用程序。 虽然聊天通常用作示例,但你可以执行更多操作。 每当用户刷新网页以查看新数据,或者页面实现 长时间轮询 以检索新数据时,适合使用 SignalR。 示例包括仪表板和监视应用程序、协作应用程序(例如同时编辑文档)、作业进度更新和实时表单。
SignalR 还支持需要来自服务器的高速更新的全新 Web 应用程序类型,例如实时游戏。
SignalR 提供了一个简单的 API,用于创建服务器到客户端远程过程调用(RPC),用于从服务器端 .NET 代码调用客户端浏览器(和其他客户端平台)中的 JavaScript 函数。 SignalR 还包括用于连接管理的 API(例如连接和断开连接事件),以及分组连接。
SignalR 会自动处理连接管理,并允许同时将消息广播到所有连接的客户端,例如聊天室。 还可以将消息发送到特定客户端。 客户端和服务器之间的连接是永久性的,与经典 HTTP 连接不同,该连接为每个通信重新建立。
SignalR 支持“服务器推送”功能,其中服务器代码可以使用远程过程调用(RPC)在浏览器中调用客户端代码,而不是目前在 Web 上常见的请求响应模型。
SignalR 应用程序可以使用内置和第三方横向扩展提供程序横向扩展到数千个客户端。
内置提供程序包括:
第三方提供商包括:
SignalR 是开源的,可通过 GitHub 访问。
SignalR 和 WebSocket
SignalR 使用新的 WebSocket 传输(如果可用),并在必要时回退到较旧的传输。 虽然你当然可以直接使用 WebSocket 编写应用,但使用 SignalR 意味着已经为你完成了许多需要实现的额外功能。 最重要的是,这意味着你可以对应用进行编码,以利用 WebSocket,而无需担心为旧客户端创建单独的代码路径。 SignalR 还阻止你担心 WebSocket 的更新,因为 SignalR 已更新以支持基础传输中的更改,从而为应用程序提供跨 WebSocket 版本的一致接口。
传输和回退
SignalR 是一种针对在客户端和服务器之间进行实时通信所需的某些传输的抽象。 如果可能,SignalR 首先尝试建立 WebSocket 连接。 WebSocket 是 SignalR 的最佳传输,因为它具有以下功能:
- 最高效的服务器内存使用。
- 最低延迟。
- 最基础的功能,例如客户端和服务器之间的全双工通信。
- WebSocket 对服务器的要求是最严格的。
- 在 Windows Server 2012 或 Windows 8 上运行。
- .NET Framework 4.5。
如果未满足这些要求,SignalR 会尝试使用其他传输进行连接。
HTML 5 传输协议
这些传输依赖于对 HTML 5 的支持。 如果客户端浏览器不支持 HTML 5 标准,将使用较旧的传输。
- WebSocket (如果服务器和浏览器都指示它们可以支持 Websocket)。 WebSocket 是唯一一种在客户端和服务器之间建立真正持久双向连接的传输。 但是,WebSocket 也具有最严格的要求:它仅在 Internet Explorer、Google Chrome 和 Mozilla Firefox Microsoft 的最新版本中完全受支持,并且仅在其他浏览器(如 Opera 和 Safari)中具有部分实现。
- 服务器发送事件(也称为 EventSource)(如果浏览器支持服务器发送事件,这基本上是 Internet Explorer 以外的所有浏览器)。
彗星传输
以下传输基于 Comet Web 应用程序模型,其中浏览器或其他客户端维护长时间保留的 HTTP 请求,服务器可以使用该请求将数据推送到客户端,而无需客户端专门请求它。
- 永久帧(仅适用于 Internet Explorer)。 Forever Frame 创建一个隐藏的 IFrame,向服务器上的一个不会完成请求的终结点发出请求。 然后,服务器会持续将脚本发送到立即执行的客户端,提供从服务器到客户端的单向实时连接。 从客户端到服务器的连接使用与服务器到客户端连接的单独连接,并且与标准 HTTP 请求一样,将为需要发送的每个数据段创建一个新连接。
- 阿贾克斯长期投票。 长轮询不会创建持久连接,而是通过一个保持打开的请求轮询服务器,直到服务器响应为止,此时连接关闭,并立即请求新连接。 这可能会导致连接重置时出现一些延迟。
有关哪些配置支持哪些传输的详细信息,请参阅 支持的平台。
传输选择过程
以下列表显示了 SignalR 用于确定要使用的传输的步骤。
如果浏览器是 Internet Explorer 8 或更早版本,则使用长轮询。
如果配置了 JSONP(即在启动连接时设置参数
jsonp为true),则使用长轮询。如果正在建立跨域连接(也就是说,如果 SignalR 终结点与托管页面不在同一域中),则满足以下条件时将使用 WebSocket:
客户端支持 CORS(跨源资源共享)。 有关哪些客户端支持 CORS 的详细信息,请参阅 caniuse.com 中的 CORS。
客户端支持 WebSocket
服务器支持 WebSocket
如果不满足上述任何一个标准,将使用长轮询。 有关跨域连接的详细信息,请参阅 如何建立跨域连接。
如果未配置 JSONP 并且连接不是跨域,则客户端和服务器都支持它时,将使用 WebSocket。
如果客户端或服务器不支持 WebSocket,则使用服务器发送事件(如果可用)。
如果服务器发送事件不可用,则尝试使用“Forever Frame”技术。
如果 Forever Frame 失败,则使用长轮询。
监视传输
可以通过在枢纽上启用日志记录,并在浏览器中打开控制台窗口,来确定应用程序使用的通讯方式。
若要在浏览器中启用中心事件的日志记录,请将以下命令添加到客户端应用程序:
$.connection.hub.logging = true;
在 Internet Explorer 中,按 F12 打开开发人员工具,然后单击“控制台”选项卡。
在 Chrome 中,按 Ctrl+Shift+J 打开控制台。
打开控制台并启用日志记录后,你将能够看到 SignalR 正在使用哪些传输。
指定传输
协商传输需要一定的时间和客户端/服务器资源。 如果已知客户端功能,则可以在启动客户端连接时指定传输。 以下代码片段演示如何通过 Ajax Long Polling 传输启动连接,此情况下会在已知客户端不支持任何其他协议时使用。
connection.start({ transport: 'longPolling' });
如果希望客户端按顺序尝试特定传输,可以指定回退顺序。 以下代码片段演示了尝试使用 WebSocket,若失败则直接切换到 Long Polling。
connection.start({ transport: ['webSockets','longPolling'] });
用于指定传输的字符串常量定义如下:
webSocketsforeverFrameserverSentEventslongPolling
连接和枢纽
SignalR API 包含两种在客户端和服务器之间通信的模型:持久连接和中心。
连接表示一个简单的终结点,用于发送单一收件人、群组或广播消息。 持久连接 API(由 PersistentConnection 类在 .NET 代码中表示)使开发人员可以直接访问 SignalR 公开的低级别通信协议。 对于使用基于连接的 API(如 Windows Communication Foundation)的开发人员来说,使用连接通信模型将很熟悉。
中心是基于连接 API 构建的更高级别管道,允许客户端和服务器直接调用彼此的方法。 SignalR 处理跨计算机边界的调度,仿佛是魔法一般,使客户端能够像调用本地方法一样轻松地调用服务器上的方法,反之亦然。 对于使用远程调用 API(如 .NET 远程处理)的开发人员来说,使用中心通信模型会很熟悉。 使用中心还可以将强类型参数传递给方法,从而启用模型绑定。
体系结构图
下图显示了中心、持久连接与用于传输的基础技术之间的关系。
中心的工作原理
当服务器端代码在客户端上调用方法时,将跨活动传输发送一个数据包,其中包含要调用的方法的名称和参数(当对象作为方法参数发送时,它使用 JSON 序列化)。 然后,客户端将方法名称与客户端代码中定义的方法匹配。 如果存在匹配项,将使用反序列化的参数数据执行客户端方法。
可以使用 Fiddler 等工具监视方法调用。下图显示了从 SignalR 服务器发送到 Fiddler“日志”窗格中的 Web 浏览器客户端的方法调用。 方法调用是从名为MoveShapeHub的枢纽发送的,被调用的方法名为updateShape。
在此示例中,中心名称使用 H 参数标识;方法名称使用 M 参数标识,并将发送到该方法的数据与 A 参数标识。 生成此消息的应用程序是在 High-Frequency Realtime 教程中创建的。
选择通信模型
大多数应用程序都应使用中心 API。 连接 API 可在以下情况下使用:
- 需要指定发送的实际消息的格式。
- 开发人员更喜欢使用消息传递和调度模型,而不是远程调用模型。
- 正在移植使用消息传送模型的现有应用程序,以使用 SignalR。