SignalR推送功能的集成

因为项目需要,需要实现消息推送的功能,为实现消息的推送,微软已经存在成熟的开源框架SignalR。

1. SignalR简介

ASP.NET SignalRASP.NET开发人员的一个库,它简化了向应用程序添加实时Web功能的过程。实时网络功能是在服务器代码可用时立即向连接的客户端推送内容的功能,而不是让服务器等待客户端请求新数据。SignalR提供了一个简单的API,用于创建从服务器端.NET代码调用客户端浏览器(和其他客户端平台)中的JavaScript函数的服务器到客户端的远程过程调用(RPC)。SignalR还包括用于连接管理(例如,连接和断开连接事件)和分组连接的API

2. SignalR传输机制

SignalR在可用的情况下使用新的WebSocket传输,并在必要时回退到较旧的传输。

SignalR是对在客户端和服务器之间进行实时工作所需的一些传输的抽象。

SignalR连接以HTTP方式启动,如果可用,则会将其提升为WebSocket连接。WebSocketSignalR的理想传输方式,因为它使服务器内存的使用效率最高,延迟最低,并具有最基本的功能(例如客户端和服务器之间的全双工通信),但它也有最严格的要求:WebSocket要求服务器使用Windows Server 2012Windows 8以及.NET Framework 4.5。如果这些要求不符合,SignalR将尝试使用其他传输进行连接

2.1. HTML 5传输

这些传输依赖于对HTML 5支持。如果客户端浏览器不支持HTML 5标准,则将使用较旧的传输。

WebSocket(如果服务器和浏览器都表示可以支持WebSocket)。WebSocket是在客户机和服务器之间建立一个真正的永久性双向连接的唯一传输方式。但是,WebSocket也有最严格的要求它仅在最新版本的Microsoft Internet ExplorerGoogle ChromeMozilla Firefox中得到完全支持,并且只在其他浏览器(如OperaSafari)中部分实现。

服务器发送事件,也称为EventSource(如果浏览器支持Server Sent Events,基本上所有浏览器都是Internet Explorer除外)

2.2. 彗星运输

以下传输基于Comet Web应用程序模型,其中浏览器或其他客户端维护长时间的HTTP请求,服务器可以使用该请求将数据推送到客户端,而无需客户端特别请求。

Forever Frame(仅适用于Internet Explorer)。Forever Frame创建一个隐藏的IFrame,向服务器上的一个未完成的端点发出请求。然后,服务器不断发送脚本到立即执行的客户端,提供从服务器到客户端的单向实时连接。从客户端到服务器的连接使用从服务器到客户端连接的单独连接,并且像标准HTTP请求一样,为每个需要发送的数据创建一个新的连接。

Ajax长时间轮询。长轮询不会创建一个持久连接,而是用一个保持打开的请求轮询服务器,直到服务器响应,此时连接关闭,并立即请求一个新的连接。这可能会在连接重置时引入一些延迟。

2.3. 传输切换

1.如果浏览器是Internet Explorer 8或更低版本,则使用长轮询。

2.如果配置了JSONP(即连接启动时jsonp设置为参数true),则使用长轮询。

3.如果正在进行跨域连接(即,如果SignalR端点与宿主页面不在同一个域中),那么如果满足以下条件,将使用WebSocket

(1) 客户端支持CORS(跨源资源共享)。

(2) 客户端支持WebSocket

(3) 该服务器支持WebSocket

如果任何这些标准不符合,将使用长轮询。

4.如果JSONP没有配置,并且连接不是跨域的,如果客户端和服务器都支持,将使用WebSocket

5.如果客户端或服务器不支持WebSocket,则使用服务器已发送事件(如果可用)。

6.如果服务器发送的事件不可用,则尝试Forever Frame

7.如果Forever Frame失败,则使用长轮询。

3. 连接和集线器

SignalR API包含两种用于在客户端和服务器之间进行通信的模型:持久连接和集线器。

Connection表示用于发送单收件人,分组或广播消息的简单终端。PersistentConnection API(由PersistentConnection类的.NET代码表示)为开发人员提供了对SignalR公开的低级通信协议的直接访问。对于使用基于连接的API(如Windows Communication Foundation)的开发人员,使用Connections通信模型将会很熟悉。

集线器是基于连接API构建的更高级别的管道,允许您的客户端和服务器直接相互调用方法。SignalR像魔术一样处理跨机器边界的调度,允许客户端像本地方法一样方便地调用服务器上的方法,反之亦然。对于使用远程调用API(如.NET Remoting)的开发人员来说,使用Hubs通信模型将会很熟悉。使用集线器还允许您将强类型参数传递给方法,从而启用模型绑定。

4. 体系结构图

5. 安装signalR

使用Nuget安装SignalR 2.2.2,安装后会自动的将SignalR依赖的其他组件同时安装。

6 SignalR服务端

服务端需要处理跨域提醒的问题,以及Redis缓存用户链接的支持。

添加OWIN启动类StartUp.cs ,并配置如下:

增加SignalR集线器类(v2RemindHub.cs,在集线器Hub类中增加相关的提醒方法:广播、按用户提醒。

按用户提醒,用户提醒的链接需要存在在Redis服务器,使用用户ID作为主键,connectionid作为值,需要集成nuget中的Microsoft.Web.RedisSessionStateProvider实现。

在主页面增加相关的JS方法,实现在页面的弹窗提醒。

需要注意的是在JavaScript中,对服务器类及其成员的引用是驼峰式的。代码示例在JavaScript中引用CChatHub类作为chatHub

7. SignalR客户端

nuget安装Microsoft.AspNet.SignalR.Client组件,以使用SignalR相关方法,完成向服务端的消息推送。

可封装client组件方法,实现后端消息推送的方法。

前端消息推送方法

$(function () {
             var remind = $.connection.remindHub;
             remind.client.SendMessage = function (message, url) {

                 var encodedmessage = $('<div />').text(message).html();
                 $('<div class="reminder alert alert-info" style="cursor: pointer; margin-bottom:5px;width: 400px; height: 50px;">'
                     + '<button type="button" class="close" data-dismiss="alert" onclick="$(this).parent().slideUp();">×</button>'
                     + '<h4 style="padding-bottom: 10px;">您收到一条新的提醒!</h4><strong></strong></div>')
                     .slideDown('slow', function () {
                         var reminder = this;
                         var timer = setTimeout(function () {
                             $(reminder).slideUp();
                             clearTimeout(timer);
                         }, 3000);
                     })
                     .prependTo('#RemindList')
                     .find("strong")
                     .html(encodedmessage).off('click').on('click', function () {
                         //if (url && url != '') {
                         //    $('#main').attr('src', url);
                         //}
                         console.log('message click');
                     });
             };
             $.connection.hub.logging = true;
             $.connection.hub.start().done(function () {
                 console.log('connection start ');
             }).fail(function (error) {
                 console.log('Invocation of start failed. Error:' + error)
             });
             $.connection.hub.disconnected(function () {
                 if ($.connection.hub.lastError) {
                     console.log("Disconnected. Reason: " + $.connection.hub.lastError.message);
                 }
             });
         });

猜你喜欢

转载自www.cnblogs.com/dpwow/p/9629268.html