[Asp.net 開發系列之SignalR篇]專題一:Asp.net SignalR快速入門

来源:http://www.cnblogs.com/zhili/archive/2016/04/02/SignalRQuickStart.html
-Advertisement-
Play Games

一、前言 之前半年時間感覺自己有點浮躁,導致停頓了半年多的時間沒有更新博客,今天重新開始記錄博文,希望自己可以找回初心,繼續沉澱。由於最近做的項目中用到SignalR技術,所以打算總結下Asp.net SignalR的相關內容,希望對剛接觸或者接觸不多的朋友有所幫助。今天的專題就是讓大家可以快速的上 ...


一、前言

  之前半年時間感覺自己有點浮躁,導致停頓了半年多的時間沒有更新博客,今天重新開始記錄博文,希望自己可以找回初心,繼續沉澱。由於最近做的項目中用到SignalR技術,所以打算總結下Asp.net SignalR的相關內容,希望對剛接觸或者接觸不多的朋友有所幫助。今天的專題就是讓大家可以快速的上手Asp.net SignalR。廢話不多說了,下麵正式進入今天專題的內容。

二、Asp.net SignalR 是個什麼東東

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

  SignalR內部有兩類對象:

  1. Http持久連接(Persisten Connection)對象:用來解決長時間連接的功能。還可以由客戶端主動向伺服器要求數據,而伺服器端不需要實現太多細節,只需要處理PersistentConnection 內所提供的五個事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
  2. Hub(集線器)對象:用來解決實時(realtime)信息交換的功能,服務端可以利用URL來註冊一個或多個Hub,只要連接到這個Hub,就能與所有的客戶端共用發送到伺服器上的信息,同時服務端可以調用客戶端的腳本。

  SignalR將整個信息的交換封裝起來,客戶端和伺服器都是使用JSON來溝通的,在服務端聲明的所有Hub信息,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理對象,而Proxy的內部則是將JSON轉換成對象。

  客戶端和服務端的具體交互情況如下圖所示:

Invoking methods with SignalR

  從上面的介紹可以看出,SignalR既然是為實時而生的,這樣就決定了其使用場所。具體適用情景有如下幾點:

  1. 聊天室,如線上客服系統,IM系統等
  2. 股票價格實時更新
  3. 消息的推送服務
  4. 游戲中人物位置的實時推送

   目前,我所在公司在開發的就是線上客服系統。

三、使用Asp.net SignalR在Web端實現廣播消息

   通過第二部分的介紹,相信大家對Asp.net SignalR有了一個初步的瞭解,接下來通過兩個例子來讓大家加深對SignalR運行機制的理解。第一個例子就是在Web端如何使用SignalR來實現廣播消息。

  1. 使用Visual Studio 2013,創建一個MVC工程
  2. 通過Nuget安裝SignalR包。右鍵引用-》選擇管理Nuget程式包-》在出現的視窗中輸入SignalR來找到SignalR包進行安裝。
  3. 安裝SignalR成功後,SignalR庫的腳本將被添加進Scripts文件夾下。具體如下圖所示:

  4. 向項目中添加一個SignalR集線器(v2)並命名為ServerHub。

  5. 將下麵代碼填充到剛剛創建的ServerHub類中。

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System;

namespace SignalRQuickStart
{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'
        };

        /// <summary>
        /// 供客戶端調用的伺服器端代碼
        /// </summary>
        /// <param name="message"></param>
        public void Send(string message)
        {
            var name = GenerateRandomName(4);

            // 調用所有客戶端的sendMessage方法
            Clients.All.sendMessage(name, message);
        }

        /// <summary>
        /// 產生隨機用戶名函數
        /// </summary>
        /// <param name="length">用戶名長度</param>
        /// <returns></returns>
        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();
        }
    }
}

  6. 創建一個Startup類,如果開始創建MVC項目的時候沒有更改身份驗證的話,這個類會預設添加的,如果已有就不需要重覆添加了。按照如下代碼更新Startup類。

  7. 在Home控制器中創建一個Home Action方法

public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }

        public ActionResult Chat()
        {
            return View();
        }
    }

  8. 在Views文件中Home文件夾中創建一個Chat視圖,視圖代碼如下所示:

@{
    ViewBag.Title = "聊天視窗";
}

<h2>Chat</h2>

<div class="container">
    <input type="text" id="message" />
    <input type="button" id="sendmessage" value="Send" />
    <input type="hidden" id="displayname" />
    <ul id="discussion"></ul>
</div>

@section scripts
{
    <!--引用SignalR庫. -->
    <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
     <!--引用自動生成的SignalR 集線器(Hub)腳本.在運行的時候在瀏覽器的Source下可看到 -->
    <script src="~/signalr/hubs"></script>
    
    <script>
        $(function () {
            // 引用自動生成的集線器代理
            var chat = $.connection.serverHub;
            // 定義伺服器端調用的客戶端sendMessage來顯示新消息
           
            chat.client.sendMessage = function (name, message) {
                // 向頁面添加消息
                $('#discussion').append('<li><strong>' + htmlEncode(name)
                    + '</strong>: ' + htmlEncode(message) + '</li>');
            };
           
            // 設置焦點到輸入框
            $('#message').focus();
            // 開始連接伺服器
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    // 調用伺服器端集線器的Send方法
                    chat.server.send($('#message').val());
                    // 清空輸入框信息並獲取焦點
                    $('#message').val('').focus();
                });
            });
        });
        
        // 為顯示的消息進行Html編碼
        function htmlEncode(value) {
            var encodedValue = $('<div />').text(value).html();
            return encodedValue;
        }
    </script>
    }

  9. 修改App_Start文件夾內的RoutConfig類,將Action方法預設設置為Chat.

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是如何來完成廣播消息的。運行的運行結果如下。

  從運行結果,你可以發現,在任何一個視窗輸入信息併發送,所有客戶端將收到該消息。這樣的效果在實際應用中很多,如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'
        };

        /// <summary>
        /// 供客戶端調用的伺服器端代碼
        /// </summary>
        /// <param name="message"></param>
        public void Send(string message)
        {
            var name = GenerateRandomName(4);

            // 調用所有客戶端的sendMessage方法
            Clients.All.sendMessage(name, message);
        }

        /// <summary>
        /// 客戶端連接的時候調用
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            Trace.WriteLine("客戶端連接成功");
            return base.OnConnected();
        }

        /// <summary>
        /// 產生隨機用戶名函數
        /// </summary>
        /// <param name="length">用戶名長度</param>
        /// <returns></returns>
        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();
        }
    }

 

  這樣在運行頁面的時候,將在輸出視窗看到“客戶端連接成功”字樣。運行效果如下圖所示:

  在第二部分介紹的時候說道,在服務端聲明的所有Hub信息,都會生成JavaScript輸出到客戶端,為了驗證這一點,可以在Chrome中F12來查看源碼就明白了,具體如下圖所示:

 

  看到上圖,你也就明白了為什麼Chat.cshtml頁面需要引入"signalr/hubs"腳本庫了吧。

<!--引用SignalR庫. -->
    <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
     <!--引用自動生成的SignalR 集線器(Hub)腳本.在運行的時候在瀏覽器的Source下可看到 -->
    <script src="~/signalr/hubs"></script>
    

 

四、在桌面程式中如何使用Asp.net SignalR

   上面部分介紹了SignalR在Asp.net MVC 中的實現,這部分將通過一個例子來看看SignalR在WPF或WinForm是如何使用的。其實這部分實現和Asp.net MVC中非常相似,主要不同在於,Asp.net MVC中的SignalR伺服器寄宿在IIS中,而在WPF中應用,我們把SignalR寄宿在WPF客戶端中。

下麵讓我們看看SignalR服務端的實現。

 

/// <summary>
        /// 啟動SignalR服務,將SignalR服務寄宿在WPF程式中
        /// </summary>
        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();
        }

        /// <summary>
        /// 發送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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<string, string>("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實現一對一的聊天。

  本文所有源碼:SignalR快速入門

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文引自鏈接http://www.52rd.com/Blog/Detail_RD.Blog_imjacob_16830.html?WebShieldDRSessionVerify=COR6tnpfsOXExxEAO6Z6 本文引自鏈接http://www.52rd.com/Blog/Detail_R ...
  • 今天安裝好rhel-server-6.6-i386後,再安裝VirtualBox成功,但是再VirtualBox中創建虛擬機的時候出現了“不能為xx虛擬機打開新任務” 並彈出如下的錯誤信息: 按照提示運行 #/sbin/rcvboxdrv setup 但是還是失敗 Stopping VirtualB ...
  • 使用svgalib 下載地址:https://launchpad.net/ubuntu/+source/svgalib/1:1.4.3-30svgalib_1.4.3.orig.tar.gzsvgalib_1.4.3-30.debian.tar.gzsvgalib_1.4.3-30.dsc 打補丁t ...
  • 網站部署之~Windows Server | 本地部署:http://www.cnblogs.com/dunitian/p/4822808.html#iis 添加角色 基本功能 預設即可 裝一下iis 選4.5和iis核心 其他的下麵繼續選 安全肯定全要的,常見HTTP和應用程式開發都是要部分安裝的 ...
  • 最近在開發中,需要在微信實現頁面點擊 撥打電話 實現一鍵撥打電話功能。 通過在網上搜索,大約都是2013年的博客和文章是這樣的說法 : 一般的web頁面用 JS實現一鍵撥打電話功能 : <a href="tel:10010">撥打電話</a> ,但在開發中發現微信上會屏蔽常規撥號功能。 因為微信有白 ...
  • Razor語法是在MVC3.0引入的全新的c#語法,取而代之<%...%>語法.用在mvc的view頁面. 首先談一下razor語法的基本用法: 1.如果在頁面輸出單一變數時,只要在c#語句之前加上@符號即可,範例如下: <p> 現在時刻:@DateTime.Now </p> 2、在頁面中輸出一段含 ...
  • 前言 ActionLink用於生成超鏈接,方法用於指向Controller的Action。 擴展方法與參數說明 ActionLink擴展方法如下: 參數類型說明如下: 重載格式 重載方法一: ActionLink(this HtmlHelper htmlHelper, string linkText ...
  • 這裡體現出閉包的數據共用 這裡體現出閉包的局部變數升級為成員變數 (在拉姆達表達式生成的匿名類中不會不會隨著方法執行完後彈棧 而是隨著回調函數徹底執行完後才被回收) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...