首頁  >  文章  >  後端開發  >  Asp.NET MVC中使用SignalR實作推送功能

Asp.NET MVC中使用SignalR實作推送功能

高洛峰
高洛峰原創
2016-12-24 13:59:411608瀏覽

一、簡介

Signal 是微軟支援的一個運行在 Dot NET 平台上的 html websocket 框架。它出現的主要目的是實現伺服器主動推送(Push)訊息到客戶端頁面,這樣客戶端就不必重新發送請求或使用輪詢技術來獲取訊息。
可造訪其官方網站:https://github.com/SignalR/ 取得更多資訊。 

二、Asp.net SignalR 是什麼東東

Asp.net SignalR是微軟為實現即時通訊的一個類別庫。一般情況下,SignalR會使用JavaScript的長輪詢(long polling)的方式來實作客戶端和伺服器通信,隨著Html5中WebSockets出現,SignalR也支援WebSockets通訊。另外SignalR開發的程式不僅限制於宿主在IIS中,也可以宿主在任何應用程序,包括控制台,客戶端程式和Windows服務等,另外還支援Mono,這意味著它可以實現跨平台部署在Linux環境下。

SignalR內部有兩類物件:

Http持久連接(Persisten Connection)物件:用來解決長時間連接的功能。也可以由客戶端主動向伺服器要求數據,而伺服器端不需要實作太多細節,只需要處理PersistentConnection 內所提供的五個事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
Hub(集線器)物件:用來解決即時(realtime)資訊交換的功能,服務端可以利用URL來註冊一個或多個Hub,只要連接到這個Hub,就能與所有的客戶端共享發送到伺服器上的訊息,同時服務端可以呼叫客戶端的腳本。
SignalR將整個訊息的交換封裝起來,客戶端和伺服器都是使用JSON來溝通的,在服務端聲明的所有Hub訊息,都會產生JavaScript輸出到客戶端,.NET則依賴Proxy來產生代理對象,而Proxy的內部則是將JSON轉換成物件。
SignalR既然是為即時而生的,這樣就決定了其使用場所。具體適用情境有以下幾點:
聊天室,如線上客服系統,IM系統等
股票價格即時更新
訊息的推播服務
遊戲中人物位置的即時推播
目前,我所在公司在開發的就是線上客服系統。

三、實作機制

SignalR 的實作機制與 .NET WCF 或 Remoting 是相似的,都是使用遠端代理來實作。在具體使用上,有兩種不同目的的介面:PersistentConnection 和Hubs,其中PersistentConnection 是實現了長時間的Javascript 輪詢(類似於Comet),Hub 是用來解決即時資訊交換問題,它是利用Javascript 動態載入執行方法實現的。 SignalR 將整個連接,資訊交換過程封裝得非常漂亮,客戶端與伺服器端全部使用 JSON 來交換資料。

下面就Hubs 介面的使用來講講整個流程:
1.在伺服器端定義對應的hub class;
2.在客戶端定義hub class 所對應的proxy 類別;
3.在客戶端與伺服器端建立連線(connection);
4.然後客戶端就可以呼叫proxy 物件的方法來呼叫伺服器端的方法,也就是發送request 給伺服器端;
5.伺服器端接收到request 之後,可以針對某個/群組客戶端或所有客戶端(廣播)發送訊息。

四、使用Asp.net SignalR在Web端實現廣播訊息

透過第二部分的介紹,相信大家對Asp.net SignalR有了初步的了解,接下來透過兩個例子讓大家加深對SignalR運作機制的理解。第一個例子就是在Web端如何使用SignalR來實作廣播訊息。
使用Visual Studio 2013,建立一個MVC工程
透過Nuget安裝SignalR套件。右鍵引用-》選擇管理Nuget程式包-》在出現的視窗中輸入SignalR來找到SignalR套件進行安裝。
安裝SignalR成功後,SignalR庫的腳本將會被加入到Scripts資料夾下。具體如下圖所示:

Asp.NET MVC中使用SignalR实现推送功能

向專案中新增一個SignalR集線器(v2)並命名為ServerHub。

Asp.NET MVC中使用SignalR实现推送功能

 將下面程式碼填入剛剛建立的ServerHub類別中。

using System;
using Microsoft.AspNet.SignalR;
 
namespace SignalDemo
{
 public class ServerHub : Hub
 {
 private static readonly char[] Constant =
 {
 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 'w', 'x', 'y', 'z',
 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 'W', 'X', 'Y', 'Z'
 };
 
 /// 
 /// 供客户端调用的服务器端代码
 /// 
 /// 
 public void Send(string message)
 {
 var name = GenerateRandomName(4);
 
 // 调用所有客户端的sendMessage方法
 Clients.All.sendMessage(name, message);
 }
 
 /// 
 /// 产生随机用户名函数
 /// 
 /// 用户名长度
 /// 
 public static string GenerateRandomName(int length)
 {
 var newRandom = new System.Text.StringBuilder(62);
 var rd = new Random();
 for (var i = 0; i < length; i++)
 {
 newRandom.Append(Constant[rd.Next(62)]);
 }
 return newRandom.ToString();
 }
 }
}

   


建立一個Startup類,如果開始創建MVC專案的時候沒有更改身份驗證的話,這個類會預設添加的,如果已有就不需要重複添加了。依照如下程式碼更新Startup類別。

using Microsoft.Owin;
using Owin;
 
[assembly: OwinStartupAttribute(typeof(SignalDemo.Startup))]
namespace SignalDemo
{
 public partial class Startup
 {
 #region MyRegion
 public void Configuration(IAppBuilder app)
 {
 app.MapSignalR();
 ConfigureAuth(app);
 }
 #endregion
 }
}

   

在Home控制器中建立一個Chat Action方法

using System.Web.Mvc;
 
namespace SignalDemo.Controllers
{
 public class HomeController : Controller
 {
 public ActionResult Chat()
 {
 return View();
 }
 }
}

   

在Views檔案中Home資料夾中建立一個Chat檢視,檢視程式碼

修改App_Start文件夹内的RoutConfig类,将Action方法默认设置为Chat

using System.Web.Mvc;
using System.Web.Routing;
 
namespace SignalDemo
{
 public class RouteConfig
 {
 public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 routes.MapRoute(
 name: "Default",
 url: "{controller}/{action}/{id}",
 defaults: new { controller = "Home", action = "Chat", id = UrlParameter.Optional }
 );
 }
 }
}

   

到此,我们的例子就实现完成了,接下来我们先来看看运行效果,之后再来解释到底SignalR是如何来完成广播消息的。运行的运行结果如下。

Asp.NET MVC中使用SignalR实现推送功能

从运行结果,你可以发现,在任何一个窗口输入信息并发送,所有客户端将收到该消息。这样的效果在实际应用中很多,如QQ,一登录QQ的时候都会推送腾讯广告消息。

  看完了运行结果,接下来我们来分析下代码,进而来剖析下SignalR到底是如何工作的。

  按照B/S模式来看,运行程序的时候,Web页面就与SignalR的服务建立了连接,具体的建立连接的代码就是:$.connection.hub.start()。这句代码的作用就是与SignalR服务建立连接,后面的done函数表明建立连接成功后为发送按钮注册了一个click事件,当客户端输入内容点击发送按钮后,该Click事件将会触发,触发执行的操作为: chat.server.send($('#message').val())。这句代码表示调用服务端的send函数,而服务端的Send韩式又是调用所有客户端的sendMessage函数,而客户端中sendMessage函数就是将信息添加到对应的消息列表中。这样就实现了广播消息的功能了。

  看到这里,有人是否会有疑问,前面的实现都只用到了集线器对象,而没有用到持久连接对象。其实并不是如此,$.connection这句代码就是使用持久连接对象,当然你也可以在重新OnConnected方法来查看监控客户端的连接情况,更新的代码如下所示:

public class ServerHub : Hub
 {
 private static readonly char[] Constant =
 {
 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 'w', 'x', 'y', 'z',
 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 'W', 'X', 'Y', 'Z'
 };
 
 /// 
 /// 供客户端调用的服务器端代码
 /// 
 /// 
 public void Send(string message)
 {
 var name = GenerateRandomName(4);
 
 // 调用所有客户端的sendMessage方法
 Clients.All.sendMessage(name, message);
 }
 
 /// 
 /// 客户端连接的时候调用
 /// 
 /// 
 public override Task OnConnected()
 {
 Trace.WriteLine("客户端连接成功");
 return base.OnConnected();
 }
 
 /// 
 /// 产生随机用户名函数
 /// 
 /// 用户名长度
 /// 
 public static string GenerateRandomName(int length)
 {
 var newRandom = new System.Text.StringBuilder(62);
 var rd = new Random();
 for (var i = 0; i < length; i++)
 {
 newRandom.Append(Constant[rd.Next(62)]);
 }
 return newRandom.ToString();
 }
 }

   


这样在运行页面的时候,将在输出窗口看到“客户端连接成功”字样。运行效果如下图所示:

Asp.NET MVC中使用SignalR实现推送功能

在第二部分介绍的时候说道,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,为了验证这一点,可以在Chrome中F12来查看源码就明白了,具体如下图所示:

Asp.NET MVC中使用SignalR实现推送功能

 看到上图,你也就明白了为什么Chat.cshtml页面需要引入"signalr/hubs"脚本库了吧。

 d9a5242a011f9643fec06048e19a4b77
 15f14217e8cb6d9b781ee5d30ab615942cacc6d41bbb37262a98f745aa00fbf0
 3e25afd4fb2f01a3380fa6d18193664d
9c680aa54eba498674e6e28bcbb95f282cacc6d41bbb37262a98f745aa00fbf0

五、在桌面程序中如何使用Asp.net SignalR

   上面部分介绍了SignalR在Asp.net MVC 中的实现,这部分将通过一个例子来看看SignalR在WPF或WinForm是如何使用的。其实这部分实现和Asp.net MVC中非常相似,主要不同在于,Asp.net MVC中的SignalR服务器寄宿在IIS中,而在WPF中应用,我们把SignalR寄宿在WPF客户端中。

下面让我们看看SignalR服务端的实现。

/// 
 /// 启动SignalR服务,将SignalR服务寄宿在WPF程序中
 /// 
 private void StartServer()
 {
 try
 {
 SignalR = WebApp.Start(ServerUri); // 启动SignalR服务
 }
 catch (TargetInvocationException)
 {
 WriteToConsole("一个服务已经运行在:" + ServerUri);
 // Dispatcher回调来设置UI控件状态
 this.Dispatcher.Invoke(() => ButtonStart.IsEnabled = true);
 return;
 }
 
 this.Dispatcher.Invoke(() => ButtonStop.IsEnabled = true);
 WriteToConsole("服务已经成功启动,地址为:" + ServerUri);
 }
 
public class ChatHub : Hub
 {
 public void Send(string name, string message)
 {
 Clients.All.addMessage(name, message);
 }
 
 public override Task OnConnected()
 {
 //
 Application.Current.Dispatcher.Invoke(() =>
 ((MainWindow)Application.Current.MainWindow).WriteToConsole("客户端连接,连接ID是: " + Context.ConnectionId));
 
 return base.OnConnected();
 }
 
 public override Task OnDisconnected(bool stopCalled)
 {
 Application.Current.Dispatcher.Invoke(() =>
 ((MainWindow)Application.Current.MainWindow).WriteToConsole("客户端断开连接,连接ID是: " + Context.ConnectionId));
 
 return base.OnDisconnected(true);
 }
 }
 
 public class Startup
 {
 public void Configuration(IAppBuilder app)
 {
 // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
 // 允许CORS跨域
 //app.UseCors(CorsOptions.AllowAll);
 app.MapSignalR();
 }
 }

   


通过上面的代码,我们SignalR服务端的实现就完成了,其实现逻辑与Asp.net MVC的代码类似。

接下来,让我们看看,WPF客户端是如何连接和与服务器进行通信的。具体客户端的实现如下:

public IHubProxy HubProxy { get; set; }
 const string ServerUri = "http://localhost:8888/signalr";
 public HubConnection Connection { get; set; }
 
 public MainWindow()
 {
 InitializeComponent();
 
 // 窗口启动时开始连接服务
 ConnectAsync();
 }
 
 /// 
 /// 发送消息
 /// 
 /// 
 /// 
 private void ButtonSend_Click(object sender, RoutedEventArgs e)
 {
 // 通过代理来调用服务端的Send方法
 // 服务端Send方法再调用客户端的AddMessage方法将消息输出到消息框中
 HubProxy.Invoke("Send", GenerateRandomName(4), TextBoxMessage.Text.Trim());
 
 TextBoxMessage.Text = String.Empty;
 TextBoxMessage.Focus();
 }
 
 private async void ConnectAsync()
 {
 Connection = new HubConnection(ServerUri);
 Connection.Closed += Connection_Closed;
 
 // 创建一个集线器代理对象
 HubProxy = Connection.CreateHubProxy("ChatHub");
 
 // 供服务端调用,将消息输出到消息列表框中
 HubProxy.On("AddMessage", (name, message) =>
 this.Dispatcher.Invoke(() =>
 RichTextBoxConsole.AppendText(String.Format("{0}: {1}\r", name, message))
 ));
 
 try
 {
 await Connection.Start();
 }
 catch (HttpRequestException)
 {
 // 连接失败
 return;
 }
 
 // 显示聊天控件
 ChatPanel.Visibility = Visibility.Visible;
 ButtonSend.IsEnabled = true;
 TextBoxMessage.Focus();
 RichTextBoxConsole.AppendText("连上服务:" + ServerUri + "\r");
 }

   


上面的代码也就是WPF客户端实现的核心代码,主要逻辑为,客户端启动的时候就调用Connection.Start方法与服务器进行连接。然后通过HubProxy代理类来调用集线器中Send方法,而集线器中的Send方法又通过调用客户端的addMessage方法将消息输出到客户端的消息框中进行显示,从而完成消息的推送过程。

其效果和Asp.net MVC上的效果是一样的。

总结

到这里,本专题的所有内容就结束了,这篇SignalR快速入门也是本人在学习SignalR过程中的一些心得体会,希望可以帮助一些刚接触SignalR的朋友快速入门。本篇主要实现了SignalR的广播消息的功能,可以实现手机端消息推送的功能,接下来一篇将介绍如何使用SignalR实现一对一的聊天。


更多Asp.NET MVC中使用SignalR實現推送功能相關文章請關注PHP中文網!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn