天天看點

SignalR學習筆記(一) 簡單聊天室

什麼是ASP.NET SignalR?

ASP.NET SignalR是一個友善程式員添加實時網絡通信功能的類庫。所謂的實時網絡通信功能(Real-time Web Functionality)就是需要伺服器主動推送資料到使用者用戶端,而非伺服器等待使用者用戶端請求資料的功能。以聊天室為例,當一個使用者發送群發消息之後,在所有使用者的聊天視窗中都需要顯示出這條消息,如果每個使用者用戶端都是用Ajax每隔一定時間去伺服器上拉取消息,那樣不僅效率低下并增加伺服器負擔,也不是真正意義上的實時程式。

消息傳輸機制

ASP.Net SignalR使用新的Websocket傳輸協定,他實作了浏覽器和伺服器全雙工通信(允許伺服器主動發消息給用戶端),并相容以前的長連接配接(Long poll)傳輸方式, 是以對于開發人員來說,不需要自己去維護使用何種傳輸方式,SignalR會自動根據用戶端浏覽器的版本自動切換消息傳輸方式

  • 對于IE8,會自動切換到Long poll傳輸。
  • 對于IE9及以上版本,會使用Websocket傳輸。

連接配接與樞紐

SignalR API包含2個模型來幫助用戶端與伺服器進行通信: 持久連接配接(Persistent Connections)與樞紐 (hubs).

持久連接配接負責傳輸消息,樞紐提供了一種很有趣的機制,允許開發人員在用戶端調用伺服器端方法或伺服器端調用用戶端方法。

樞紐(Hubs)是如何工作的

當伺服器端程式調用用戶端方法時,一個包含用戶端方法名及參數的Json資料包會通過持久連接配接傳輸到用戶端,用戶端會根據資料包中的方法名進行比對,如果找到相同方法名的方法,就會自動調用找到的方法,方法所需的參數值會使用資料包中對應的參數值。

簡單的聊天室

下面用一個聊天室的例子,熟悉一下SignalR的基本使用方式。

這個聊天室頁面的需求如下:

  1. 使用者打開聊天室頁面,需要首先錄入自己的昵稱,輸入昵稱之後,通知聊天室的其他使用者該使用者進入聊天室
  2. 使用者可以使用在聊天室中發送公共消息
  3. 使用者可以使用“to 使用者名 消息内容”的方式發送私聊消息

添加項目

建立一個空的ASP.NET Web Application工程

SignalR學習筆記(一) 簡單聊天室
SignalR學習筆記(一) 簡單聊天室

通過Nuget或者最新版本的SignalR庫

展開Package Manager Console面闆,輸入

install-package Microsoft.AspNet.SignalR

添加Startup.cs啟用SignalR

using Microsoft.Owin;

using Owin;

 

[assembly: OwinStartup(typeof(ChatRoom.Startup))]

 

namespace ChatRoom

{

    public class Startup

    {

        public void Configuration(IAppBuilder app)

        {

            //啟用SignalR

            app.MapSignalR();

        }

    }

}      

添加樞紐(Hub)

在工程中添加ChatRoomHub.cs, 選擇SignalR Hub Class(v2)

SignalR學習筆記(一) 簡單聊天室

替換ChatRoomHub類中的内容替換

using Microsoft.AspNet.SignalR;

using System.Collections.Generic;

using System.Linq;

 

namespace ChatRoom

{

    public class ChatRoomHub : Hub

    {

        private static Dictionary<string, string> _nickNames = new Dictionary<string, string>();

 

        public void SetNickName(string nickName)

        {

            //當Hub啟動完畢,每個連接配接到這個Hub的用戶端都會自動配置設定一個唯一的ConnectionId。

            //當SignalR向指定用戶端推送消息的時候,需要指定ConnectionId, 是以這裡需要記錄一下每個昵稱對應的用戶端ConnectionId

            _nickNames.Add(Context.ConnectionId, nickName);

 

            //當使用者設定昵稱之後,需要發送歡迎資訊到所有的使用者用戶端,調用用戶端receiveWelcomeMessage方法顯示歡迎資訊

            Clients.All.ReceiveWelcomeMessage($"{nickName}進入聊天室。");

        }

 

        public void Send(string nickName, string message)

        {

            if (string.IsNullOrWhiteSpace(nickName) || string.IsNullOrWhiteSpace(message))

            {

                //如果使用者昵稱或者消息不存在,就不做任何操作

                return;

            }

 

            if (message.StartsWith("to") && message.Split(' ').Length == 3)

            {

                //私聊消息

                var toUserName = message.Split(' ')[1];

 

                if (_nickNames.ContainsValue(toUserName))

                {

                    var connectionId = _nickNames.First(p => p.Value == toUserName).Key;

 

                    if (!string.IsNullOrWhiteSpace(connectionId) && connectionId != Context.ConnectionId)

                    {

                        Clients.Client(connectionId).ReceivePrivateMessage(nickName, message.Split(' ')[2]);

                    }

                }

            }

            else

            {

                //普通廣播消息

                if (_nickNames.ContainsValue(nickName))

                {

                    Clients.All.ReceiveBroadcastMessage(nickName, message);

                }

            }

        }

    }

}      

添加顯示頁面

添加空html檔案ChatRoom.html, 使用以下檔案替換

<!DOCTYPE html>

<html>

<head>

    <title>SignalR Simple Chat</title>

    <style type="text/css">

        .container {

            background-color: #99CCFF;

            border: thick solid #808080;

            padding: 20px;

            margin: 20px;

        }

    </style>

</head>

<body>

    <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>

    <script src="Scripts/jquery-1.6.4.min.js"></script>

    <script src="Scripts/jquery.signalR-2.2.2.min.js"></script>

    <script src="signalr/hubs"></script>

 

    <script type="text/javascript">

        $(function () {

 

            //使用代理模式, 建立用戶端的hub代理

            var chat = $.connection.chatRoomHub;

 

            //伺服器Hub中, 調用ReceiveWelcomeMessage方法時, 會執行用戶端的chat.client.receiveBroadcastMessage方法

            chat.client.receiveBroadcastMessage = function (name, message) {

 

                //防JS輸入

                var encodedName = $('<div />').text(name).html();

                var encodedMsg = $('<div />').text(message).html();

 

                $('#discussion').append('<li><strong>' + encodedName

                    + '</strong>:  ' + encodedMsg + '</li>');

            };

 

            //伺服器Hub中, 調用ReceiveWelcomeMessage方法時, 會執行用戶端的chat.client.receiveWelcomeMessage方法

            chat.client.receiveWelcomeMessage = function (message) {

                var encodedMsg = $('<div />').text(message).html();

 

                $('#discussion').append('<li><strong style="color:blue">' + encodedMsg

                    + '</strong></li>');

            };

 

            //伺服器Hub中, 調用ReceivePrivateMessage方法時, 會執行用戶端的chat.client.receivePrivateMessage方法

            chat.client.receivePrivateMessage = function (name, message) {

                var encodedName = $('<div />').text(name).html();

                var encodedMsg = $('<div />').text(message).html();

 

                $('#discussion').append('<li><strong style="color: green">' + encodedName

                    + '偷偷的跟你說</strong>:  ' + encodedMsg + '</li>');

            };

 

            //通過代理連接配接到伺服器Hub

            $.connection.hub.start().done(function () {

                $('#sendmessage').click(function () {

                    chat.server.send($('#displayname').val(), $('#message').val());

 

                    $('#message').val('').focus();

                });

 

                //連接配接成功後, 需要使用者立刻輸入昵稱

                $('#displayname').val(prompt('Enter your name:', ''));

                chat.server.setNickName($('#displayname').val());

                $('#message').focus();

            });

        });

    </script>

</body>

</html>      

最終實作效果

SignalR學習筆記(一) 簡單聊天室