溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

發(fā)布時(shí)間:2022-05-30 10:57:34 來源:億速云 閱讀:145 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天”吧!

    一:什么是signalR

    Asp.net SignalR是微軟為實(shí)現(xiàn)實(shí)時(shí)通信的一個(gè)類庫。

    一般情況下,signalR會使用JavaScript的長輪詢(long polling)的方式來實(shí)現(xiàn)客戶端和服務(wù)器通信,隨著Html5中WebSockets出現(xiàn),SignalR也支持WebSockets通信。

    另外SignalR開發(fā)的程序不僅僅限制于宿主在IIS中,也可以宿主在任何應(yīng)用程序,包括控制臺,客戶端程序和Windows服務(wù)等,另外還支持Mono,這意味著它可以實(shí)現(xiàn)跨平臺部署在Linux環(huán)境下。

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

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

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    1、SignalR傳輸方式

    1、HTML5 傳輸

    這種傳輸方式當(dāng)然是需要對HTML5兼容支持。如果客戶端不支持HTML5 標(biāo)準(zhǔn),那么你可以使用其他方式。

    • WebSocket: (前提是服務(wù)器和客戶端都可以支持WebSocket )。WebSocket 是唯一的能夠支持服務(wù)器和客戶端建立真正持久的雙向連接的傳輸方式,但是就是WebSocket要求的條件比較苛刻。 
      WebSocket真正能夠支持只是在最新的IE 瀏覽器、Chrome、Firefox和一些其他的瀏覽器比如Opera 和 Safari。 

    • Server Sent Events (SSE)服務(wù)端發(fā)送事件 :就是我們常說的EventSource (除了IE的其他瀏覽器都支持支持服務(wù)器發(fā)送事件)。

    2、Comet 傳輸

    下面的傳輸方式都是建立在Comet Web應(yīng)用模型上。這種傳輸方式會在瀏覽器或者其他客戶端保持一個(gè)長連接的HTTP請求,服務(wù)器可以利用這個(gè)請求將數(shù)據(jù)推送到客戶端,而不用等客戶端單獨(dú)去請求數(shù)據(jù)。

    • Forever Frame:(只有IE瀏覽器支持)Forever Frame 會創(chuàng)建一個(gè)隱藏的IFrame ,這個(gè)IFrame 會向服務(wù)器發(fā)起一個(gè)端點(diǎn)請求,但是這個(gè)請求不會結(jié)束。服務(wù)器會不停的發(fā)送腳本到客戶端馬上執(zhí)行,提供一個(gè)從服務(wù)器端到客戶端的單向?qū)崟r(shí)連接。服務(wù)端到客戶端和客戶端到服務(wù)端分別是兩個(gè)不同的連接,就像一個(gè)標(biāo)準(zhǔn)的HTTP請求,一旦有數(shù)據(jù)需要發(fā)送就會創(chuàng)建一個(gè)新的連接。

    • Ajax Long Polling長輪詢:長輪詢不會創(chuàng)建一個(gè)持久的連接,它是會保持一個(gè)客戶端與服務(wù)器的連接,直到服務(wù)器做出應(yīng)答就會立即關(guān)閉,然后創(chuàng)建一個(gè)新的連接。當(dāng)連接重置的時(shí)候這會導(dǎo)致一些延遲。

    2、SignalR連接模式

    • Http Persisten Connection(持久連接)對象:用來解決長時(shí)間連接的功能。 
      還可以由客戶端主動向服務(wù)器要求數(shù)據(jù),而服務(wù)器端不需要實(shí)現(xiàn)太多細(xì)節(jié),只需要處理PersistentConnection 內(nèi)所提供的五個(gè)事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。

    • Hub(集線器)對象:用來解決實(shí)時(shí)(realtime)信息交換的功能,服務(wù)端可以利用URL來注冊一個(gè)或多個(gè)Hub,只要連接到這個(gè)Hub,就能與所有的客戶端共享發(fā)送到服務(wù)器上的信息,同時(shí)服務(wù)端可以調(diào)用客戶端的腳本。 
      SignalR將整個(gè)信息的交換封裝起來,客戶端和服務(wù)器都是使用JSON來溝通的,在服務(wù)端聲明的所有Hub信息,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理對象,而Proxy的內(nèi)部則是將JSON轉(zhuǎn)換成對象。

    下面的圖展示了Hub和持久連接的關(guān)系,讓你對底層的傳輸技術(shù)一目了然。

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    二、服務(wù)端

    原文參考:教程:通過 SignalR 2 進(jìn)行實(shí)時(shí)聊天

    使用vs2012創(chuàng)建一個(gè)新的ASP.NET Web Application項(xiàng)目。

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    1、添加服務(wù)端Hub

    解決方案中添加SignalR Hub類選項(xiàng),然后創(chuàng)建文件ChatHub.cs。此步驟將創(chuàng)建ChatHub.cs類文件并添加一組腳本文件和 SignalR 支持到項(xiàng)目的程序集引用。

    注意:可以使用NuGet命令 install-package Microsoft.AspNet.SignalR 來引用SignalR到項(xiàng)目中

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    然后在ChatHub類中輸入下面這段代碼。

    using Microsoft.AspNet.SignalR;
    
    namespace WebApplication2
    {
        public class ChatHub : Hub
        {
            //定義可以被網(wǎng)頁腳本訪問的公共方法
            public void Send(string name, string message) //在客戶端可以使用hub.server.send()方法調(diào)用。
            {
                // 客戶端通過調(diào)用broadcastMessage來獲取服務(wù)端數(shù)據(jù)
                Clients.All.broadcastMessage(name, message);//在客戶端通過hub.client.broadcastMessage=function(){…}定義這個(gè)回調(diào)函數(shù)。
            }
        }
    }

    ChatHub類中,可以看到它繼承自Microsoft.AspNet.SignalR.Hub類。從Hub類派生出類是構(gòu)建SignalR應(yīng)用程序的有用方式。在這個(gè)類(ChatHub)中定義的公共方法可以被網(wǎng)頁內(nèi)的腳本訪問。

    在這段代碼中(ChatHub類),客戶端通過調(diào)用ChatHub.Send方法,并把名稱和消息內(nèi)容做為參數(shù)傳遞給ChatHub。而ChatHub則通過Clients.All.broadcastMessage方法把該消息廣播給所有客戶端。

    Send方法演示了幾個(gè)Hub概念:

    • 在hub上聲明一些公共方法,以便客戶端可以調(diào)用它們。

    • 使用Microsoft.AspNet.SignalR.Hub。客戶端動態(tài)屬性用于與連接到此中心的所有客戶端進(jìn)行通信。

    • 調(diào)用客戶機(jī)上的函數(shù)(如broadcastMessage函數(shù))來更新客戶機(jī)。

    2、添加OWIN 啟動類

    Solution Explorer中,右擊項(xiàng)目,然后添加一個(gè)名為StartupOWIN 啟動類,然后輸入下面這段代碼。

    using Microsoft.Owin;
    using Owin;
    
    [assembly: OwinStartup(typeof(WebApplication2.Startup))]
    namespace WebApplication2
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                app.MapSignalR();
            }
        }
    }

    三、客戶端

    在項(xiàng)目中添加一個(gè)靜態(tài)網(wǎng)頁文件,并命名為index.html,然后右擊該網(wǎng)頁文件,并選擇Set As Start Page,在Index.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>
    
        Reference the jQuery library. 
        <script src="Scripts/jquery-1.12.4.js"></script>
        Reference the SignalR library. 
        <script src="Scripts/jquery.signalR-2.4.1.js"></script>
        Reference the autogenerated SignalR hub script. 
        <script src="signalr/hubs"></script>
        Add script to update the page and send messages.
        <script type="text/javascript">
            $(function () {
                // 1、聲明一個(gè)代理,用于引用服務(wù)端hub
                var chat = $.connection.chatHub;
    
                // 2、創(chuàng)建一個(gè)回調(diào)函數(shù),讓Hub調(diào)用它來廣播消息。
                chat.client.broadcastMessage = function (name, message) {
                    // Html編碼形式顯示名稱和消息
                    var encodedName = $('
    ').text(name).html();
                    var encodedMsg = $('
    ').text(message).html();;
                    // 將消息添加到頁面。
                    $('#discussion').append('
    ' + encodedName
                        + ':  ' + encodedMsg + '
    ');
                };
                // 獲取用戶名
                $('#displayname').val(prompt('Enter your name:', ''));
                // 將初始焦點(diǎn)設(shè)置為消息輸入框。
                $('#message').focus();
    
                // 3、開始連接和發(fā)送消息
                $.connection.hub.start().done(function () {
                    $('#sendmessage').click(function () {
                        // 在Hub上調(diào)用Send方法.
                        chat.server.send($('#displayname').val(), $('#message').val());
                        // 清除文本框并為下一個(gè)注釋重置焦點(diǎn)。
                        $('#message').val('').focus();
                    });
                });
            });
        </script>
    </body>
    </html>

    客戶端通過jquery.signalR.jssignalr/hubs來與服務(wù)器進(jìn)行通信,首先它要聲明一個(gè)代理來引用集線器。

    var chat = $.connection.chatHub

    請注意:在JavaScript中,對服務(wù)器類及其成員的引用必須是camelCase形式。本例中將C#服務(wù)端的ChatHub類在JavaScript中的引用為chatHub。

    然后它要再定義一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)主要是為了讓服務(wù)器進(jìn)行調(diào)用,從而將數(shù)據(jù)推送到客戶端。

    chat.client.broadcastMessage = function (name, message) {
        //TODO:接收服務(wù)器推送的消息
    };

    而下面的代碼則是為了確保在將消息發(fā)送到服務(wù)器之前已經(jīng)與服務(wù)器建立了連接。.done 函數(shù)表示連接成功后為發(fā)送的按鈕綁定一個(gè)單擊事件。

    // 與服務(wù)器建立連接后才能發(fā)送消息到服務(wù)器
    $.connection.hub.start().done(function () {
        $('#sendmessage').click(function () {
            // 調(diào)用服務(wù)器端的ChatHub.Send方法,把消息發(fā)送到服務(wù)器
            chat.server.send("name", "message");
        });
    });

    保存項(xiàng)目,并按F5運(yùn)行,就可以實(shí)現(xiàn)B/S模式下的即時(shí)通訊。

    四、運(yùn)行結(jié)果

    項(xiàng)目運(yùn)行起來后,同時(shí)用多個(gè)瀏覽器打開的,輸入各自的姓名之后,就能夠?qū)崿F(xiàn)即時(shí)通訊了。回到我們的vs,還能夠看到自動生成的hubs腳本文件,如下圖所示。

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    三個(gè)不同的瀏覽器中的運(yùn)行方式。 當(dāng) Tom、 Anand 和 Susan 發(fā)送消息時(shí),所有瀏覽器實(shí)時(shí)更新:

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    在ServerHub重寫一個(gè) OnConnected 方法來監(jiān)控客戶端的連接情況,程序運(yùn)行的時(shí)候web頁面就使用$.connection.hub.start() 與signalR服務(wù)開始建立連接了,在調(diào)試的時(shí)候可以在輸入中看到 "客戶端連接成功!"

    public override Task OnConnected()
    {
        System.Diagnostics.Trace.WriteLine("客戶端連接成功!");
        return base.OnConnected();
    }

    Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天

    五、一對一聊天實(shí)例

    Clients.Client(connectionId).addMessage() 此方法的作用就是客戶端注冊addMessage方法,向指定連接Id的客戶端發(fā)送消息。一對一的聊天發(fā)送的消息也必須回發(fā)給自己,所以連接的Id可以通過Context.ConnectionId來獲取。當(dāng)然不用Client.Client(Context.ConnectionId) ,也可以使用Client.Caller()方法直接發(fā)送。

    Client.Clients(IList connectionIds) 這個(gè)方法的意思就是想一組string 的幾個(gè)ConnectionId發(fā)送消息。類似于QQ上@好友的那種功能。 

    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace WebApplication2
    {
        [HubName("UserHub")]
        public class UserHub : Hub
        {
            #region 字段
    
            public static List users = new List();
    
            #endregion 字段
    
            #region 方法
    
            //獲取所有用戶在線列表
            private void GetUsers()
            {
                var list = users.Select(s => new { s.Name, s.ConnectionID }).ToList();
                string jsonList = JsonConvert.SerializeObject(list);
                Clients.All.getUsers(jsonList);
            }
    
            //登記名字
            public void LoginIn(string name)
            {
                //查詢用戶
                var user = users.SingleOrDefault(u => u.ConnectionID == Context.ConnectionId);
                if (user != null)
                {
                    user.Name = name;//登記名字
                    Clients.Client(Context.ConnectionId).showId(Context.ConnectionId);
                }
                GetUsers();
            }
    
            //發(fā)送消息
            [HubMethodName("sendMessage")]
            public void SendMessage(string connectionId, string message)
            {
                Clients.All.hello();
                var user = users.Where(s => s.ConnectionID == connectionId).FirstOrDefault();
                if (user != null)
                {
                    Clients.Client(connectionId).addMessage(message + "" + DateTime.Now, Context.ConnectionId);
                    //給自己發(fā)送,把用戶的ID傳給自己
                    Clients.Client(Context.ConnectionId).addMessage(message + "" + DateTime.Now, connectionId);
                }
                else
                {
                    Clients.Client(Context.ConnectionId).showMessage("該用戶已離線");
                }
            }
    
            /// 
    
            /// 重寫連接事件
            /// 
            /// 
            public override Task OnConnected()
            {
                //查詢用戶
                var user = users.Where(w => w.ConnectionID == Context.ConnectionId).SingleOrDefault();
                //判斷用戶是否存在,否則添加集合
                if (user == null)
                {
                    user = new User("", Context.ConnectionId);
                    users.Add(user);
                }
                return base.OnConnected();
            }
    
            public override Task OnDisconnected(bool stopCalled)
            {
                var user = users.Where(p => p.ConnectionID == Context.ConnectionId).FirstOrDefault();
                //判斷用戶是否存在,存在則刪除
                if (user != null)
                {
                    //刪除用戶
                    users.Remove(user);
                }
                GetUsers();//獲取所有用戶的列表
                return base.OnDisconnected(stopCalled);
            }
    
            #endregion 方法
        }
    
        public class User
        {
            #region 構(gòu)造函數(shù)
    
            public User(string name, string connectionId)
            {
                this.Name = name;
                this.ConnectionID = connectionId;
            }
    
            #endregion 構(gòu)造函數(shù)
    
            #region 屬性
    
            [Key]
            public string ConnectionID { get; set; }
    
            public string Name { get; set; }
    
            #endregion 屬性
        }
    }

    到此,相信大家對“Asp.net如何通過SignalR2進(jìn)行實(shí)時(shí)聊天”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI