SignalR:ASP.NET 的套接字编程方式
什么是 SignalR?如何使用 SignalR 和 jQuery 进行实时编程?
引言
如果您一直关注着 Web/移动开发领域的快速变化,或者您正身处其中,您可能会对不断涌现的新术语/流行语感到困惑/觉得有趣/感到惊讶。
好吧,来个小测验。
MEAN 是什么? M-E-A-N,代表 Mongo db, Express, Angular js, node js。
Gulp、Grunt、React js 是什么? Ionic 框架怎么样?
嗯,如果您能了如指掌,那您就是大师中的大师!您可以获得 1000 个 Stack Overflow 赞!
如果您能了如指掌,您可能(有意或无意地)偏向于微软技术。嗯,现在已不是微软的黄金时代了。
再来个测验。
问题:SignalR 是什么? SignalR 和 Node js 有什么共同点?
答案:SignalR 是微软 ASP.NET 的套接字编程方式,“一个用于开发者在应用程序中添加实时 Web 功能的库。实时 Web 功能是指服务器端代码能够实时地将其内容推送到已连接的客户端。”
这就是它与 node js 的共同点,node js 也可以让您进行实时套接字编程。
那么,SignalR 套接字编程到底是什么?
长期以来,对于使用 JavaScript 进行客户端-服务器通信,我们使用带 http 协议的 AJAX。因此,客户端(例如,Web 浏览器)向 Web 服务器发送请求,Web 服务器发送回数据。每个请求都会启动到服务器上特定端口(80, 8080)的连接。在每个请求完成时,连接就会关闭。
现在对于 Web 套接字协议,客户端和服务器仍然需要建立连接,但是,一旦连接建立,客户端和服务器就可以来回传递消息,而无需重新建立新的连接。
如果我要向一个 6 岁的孩子解释,我会这样解释
假设您的爸爸正在家里干活,他发现他需要一个您朋友的爸爸正好有的特殊工具。您的朋友就住在隔壁。所以您爸爸打电话给您朋友的爸爸,去他家借工具。然后门就关上了。下次您爸爸需要还工具时,他需要再次打电话。
上面就是 http 协议。您爸爸发起一个请求;邻居提供“数据”/工具。然后,连接就关闭了。
现在,您想和您的朋友玩,您的朋友有很多玩具。你们两个都得到了父母的许可。您的朋友把门开着;您可以随意进出他家拿任何您需要的东西。在这段时间里,你们谁也不需要再次请求许可。
您可能会称之为 Web 套接字协议。一旦您和您的朋友建立了连接,您和您的朋友就可以开始交流、互相给予,而无需再进行任何许可、敲门等操作。
如何使用 SignalR?
对于下面的示例应用程序,我们将加载一个任务列表,并使用 jQuery 数据表进行显示。之后,我们将实时更新这些任务的状态(模拟)。您可以在这里查看完整代码。
首先,我们来设置项目并通过 nuget 添加 SignalR。
让我们继续创建一个全新的项目。
- 在 Visual Studio 中,创建一个 ASP.NET Web 应用程序。
- 请选择“Empty”作为您的模板。
- 让 Visual Studio 完成您的 Web 应用程序的创建。
- 在解决方案资源管理器中,右键单击您的解决方案,然后单击“管理解决方案的 NuGet 程序包”,搜索 SignalR,然后安装 Microsoft ASP.NET SignalR。
这样,它应该会安装所有 SignalR 所需的组件。
请确保您也安装了 json .NET。
好了,安装完毕后,我们可以直接开始工作,创建一个集线器(hub)并设置我们的客户端。
等一下,什么是 hub
?
所以,对于 SignalR 来说,hub
就像是 ASP.NET MVC API 的控制器。一个 hub 是一个服务器端类,其中包含您的客户端代码可以调用的各种方法。一个 hub 可以直接将数据返回给客户端,或者可以在数据可用时将其推送到客户端。
现在可能还不太明白,但我们继续。
让我们创建一个名为 TaskHub
的 hub,它继承自 SignalR.hub
类。
请注意,我还创建了一个 taskService
来处理实际的繁重工作。我的 taskHub
充当客户端和服务器之间的接口。
请查看TaskService 代码
。
[HubName("taskHub")]
public class Taskhub : Hub
{
private readonly TimeSpan _updateInterval = TimeSpan.FromMilliseconds(1000);
private static int currentId = 0;
private Timer _timer;
public List<faketask> GetTasks()
{
return new TaskService().GetAllTasks();
}
public void UpdateTasks()
{
_timer = new Timer(UpdateTaskStatus, null, _updateInterval, _updateInterval);
}
private void UpdateTaskStatus(Object state)
{
var tS = new TaskService();
var task = tS.UpdateTask(currentId%10);
currentId++;
Clients.All.updateTaskStatus(task);
}
}
所以,在我的 TaskHub
中,我有 2 个方法,一个方法是获取所有任务并立即返回给客户端。
public List<faketask> GetTasks()
{
return new TaskService().GetAllTasks();
}
另一个方法是周期性地逐个更新任务状态,并通知所有连接到此集线器的客户端
Clients.All.updateTaskStatus(task);
让我们看看客户端如何发起连接,设置一个集线器可以调用的方法,以及调用一个集线器的方法。
让我们设置一个简单的 HTML 页面,包含几个最基本控件:一个用于调用更新状态的按钮,一个显示所有任务的 jQuery datatable
。很简单吧?现在稍微注意一下底部,我们需要包含的一组 JavaScript 文件
<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR.min.js" type="text/javascript"></script>
<script src="SignalR/hubs"></script>
嗯,jQuery 就是 jQuery。jQuery.signalR 是 SignalR JavaScript 客户端,以 jQuery 插件的形式存在,第三个 signalR/hubs 是生成的 hub 代理。
(注意:不幸的是,SignalR 完全依赖于 jQuery。社区曾强烈呼吁其独立(摆脱 jQuery),微软团队在 2 年前敷衍了事地承诺过会实现,但尚未实现。
嗯,对于这个示例应用程序来说,这真的不是问题。但对于非 jQuery 用户来说,这确实很麻烦。例如,我希望在我的 Ext js 应用程序中不必包含 jQuery。)
一旦我们包含了必要的 JavaScript 库文件,我们就可以开始使用所有 SignalR 的功能了。
首先,我们启动连接,然后调用我们自己的 init
函数,该函数调用我们的服务器端 hub 方法来生成任务列表,并使用我们的数据表进行显示。
// Start the connection
$.connection.hub.start()
.then(init);
function init() {
return taskHub.server.getTasks().done(function (data) {
//handle data right here.
});
}
请注意,在服务器端,集线器是如何直接调用客户端的,而在客户端,JavaScript 也是直接调用服务器的。客户端接收和处理来自集线器发送的数据有两种方式。如果集线器能够立即返回数据,您可以直接在 done 中指定回调函数。
是的,您猜对了。这和 jQuery 的 ajax
done
一模一样。
$.ajax({
url: "http://fiddle.jshell.net/favicon.png",
}).done(function( data ) {
});
但是,如果您的服务器/集线器需要持续地将数据推送到客户端,或者它只是需要异步运行,集线器可以返回 void
,同时,选择直接调用 JavaScript 函数来通知客户端。
Clients.All.updateTaskStatus(task);
当然,客户端会提供如下方法
// Add client-side hub methods that the server will call
$.extend(taskHub.client, {
updateTaskStatus: function (task) {
}
});
好的,这差不多就是这个小型 SignalR 应用程序所需的所有代码了。
要运行它,按 F5,希望您能看到以下景象
当您单击更新时,您将看到任务神奇地完成,并大约每秒更新一次。
或者,您将看到错误。
当事情出错时…
您可能会在 SignalR 应用程序中遇到一些常见错误。
- signalr/hubs 未生成…
当您没有收到数据时,打开您的开发工具,您可能会看到类似 signalr/hubs not generated 的错误消息。
原因/解决方案
通常,这仅仅意味着您为动态生成的代理 js 指定的路径不正确。它通常应该在应用程序的根目录。对于 ASP.NET MVC 4 或 5 Razor 视图。或者只需检查您的应用程序根目录。
<script src="~/signalr/hubs"></script>
- 找不到包含 OwinStartupAttribute 的程序集…
Stackoverflow 有一些关于此错误的问答。还有一个完整的文章也对此进行了介绍。
基本上,您需要确保您有一个具有
OwinStartup
属性的启动类[assembly: OwinStartup(typeof(StartupDemo.TestStartup))]
或者在
appsettings
中指定它<appSettings> <add key="owin:appStartup" value="StartupDemo.ProductionStartup" /> </appSettings>
事实上,如果您耐心一点,您会发现微软在他们的SignalR 学习版块中有大量的相关信息。
结束语
嗯,就像任何新技术一样,刚开始学习时,您可能会遇到各种不便,并且在做基本操作时可能会感到沮丧,您可能会渴望回到熟悉的技术的舒适区。对于 SignalR 来说,情况尤其如此。
但是,稍微坚持一下,您可能会开始喜欢它。它可能成为您的救命稻草,特别是当您的应用程序需要实时注入能量时,在这个移动无处不在、一切皆有可能的世界里,每一个应用程序都需要。
注意
完整的代码可以从Github下载或克隆。