65.9K
CodeProject 正在变化。 阅读更多。
Home

SignalR:ASP.NET 的套接字编程方式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.46/5 (13投票s)

2015 年 8 月 14 日

CPOL

7分钟阅读

viewsIcon

32364

什么是 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。

让我们继续创建一个全新的项目。

  1. 在 Visual Studio 中,创建一个 ASP.NET Web 应用程序。

  2. 请选择“Empty”作为您的模板。

  3. 让 Visual Studio 完成您的 Web 应用程序的创建。
  4. 在解决方案资源管理器中,右键单击您的解决方案,然后单击“管理解决方案的 NuGet 程序包”,搜索 SignalR,然后安装 Microsoft ASP.NET SignalR。

这样,它应该会安装所有 SignalR 所需的组件。

请确保您也安装了 json .NET。

好了,安装完毕后,我们可以直接开始工作,创建一个集线器(hub)并设置我们的客户端。

等一下,什么是 hub

所以,对于 SignalR 来说,hub 就像是 ASP.NET MVC API 的控制器。一个 hub 是一个服务器端类,其中包含您的客户端代码可以调用的各种方法。一个 hub 可以直接将数据返回给客户端,或者可以在数据可用时将其推送到客户端。

现在可能还不太明白,但我们继续。

让我们创建一个名为 TaskHubhub,它继承自 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 应用程序中遇到一些常见错误。

  1. signalr/hubs 未生成

    当您没有收到数据时,打开您的开发工具,您可能会看到类似 signalr/hubs not generated 的错误消息。

    原因/解决方案

    通常,这仅仅意味着您为动态生成的代理 js 指定的路径不正确。它通常应该在应用程序的根目录。对于 ASP.NET MVC 4 或 5 Razor 视图。或者只需检查您的应用程序根目录。

    <script src="~/signalr/hubs"></script>
  2. 找不到包含 OwinStartupAttribute 的程序集

    Stackoverflow 有一些关于此错误的问答。还有一个完整的文章也对此进行了介绍。

    基本上,您需要确保您有一个具有 OwinStartup 属性的启动类

        [assembly: OwinStartup(typeof(StartupDemo.TestStartup))]

    或者在 appsettings 中指定它

        <appSettings> 
          <add key="owin:appStartup" value="StartupDemo.ProductionStartup" />
        </appSettings>

    事实上,如果您耐心一点,您会发现微软在他们的SignalR 学习版块中有大量的相关信息。

结束语

嗯,就像任何新技术一样,刚开始学习时,您可能会遇到各种不便,并且在做基本操作时可能会感到沮丧,您可能会渴望回到熟悉的技术的舒适区。对于 SignalR 来说,情况尤其如此。

但是,稍微坚持一下,您可能会开始喜欢它。它可能成为您的救命稻草,特别是当您的应用程序需要实时注入能量时,在这个移动无处不在、一切皆有可能的世界里,每一个应用程序都需要。

注意

完整的代码可以从Github下载或克隆。

© . All rights reserved.