1. 程式人生 > >史上最全面的SignalR系列教程-5、SignalR 實現一對一聊天

史上最全面的SignalR系列教程-5、SignalR 實現一對一聊天

1、概述

通過前面幾篇文章

史上最全面的SignalR系列教程-1、認識SignalR

史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式

史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式

史上最全面的SignalR系列教程-4、SignalR 自託管全解(使用Self-Host)-附各終端詳細例項

RDIFramework.NET敏捷開發框架通過SignalR技術整合即時通訊(IM)

我們對SignalR算入門了,知道如何把SignalR合理應用到實際的專案中。前面的文章主要講解的是SignalR的概念,託管方式,以及推送的功能。本篇主要講解通過SignalR實現一對一、點對點的聊天。

2、SignalR一對一聊天實現

2.1、 建立ASP.NET Mvc專案

新建一個空的ASP.NET Mvc專案,取名為:SignalROneToOne,如下圖所示。為了整個系列的完整性,我們直接在上一專案的基礎上新增的一個測試專案,後面有專案的原始碼託管地址。

2.2、安裝Nuget包

建立好專案後,要使用SignalR,需要先安裝SignalR包,可以通過程式包管理控制檯輸入包安裝命令進行安裝。

Install-Package Microsoft.AspNet.SignalR

也可以使用介面方式,如下圖所示。

2.3、一對一聊天后臺程式碼實現

向工程中新增HubConnections目錄,在其中新增OneToOneHub.cs檔案,如下圖所示:

實現的主要步驟:

  1. 重寫OnConnected連線方法和OnDisconnected斷開方法。
  2. 使用SendMessage伺服器端方法傳送訊息,GetName獲取使用者名稱。
  3. 客戶端響應的提示返回資訊方法,如Clients.Client(Context.ConnectionId).addMessage(message)

OneToOneHub程式碼內容如下:

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 SignalROneToOneDemo.Connections
{
    /// <summary>
    /// 使用者實體類
    /// </summary>
    public class User
    {
        /// <summary>
        /// 連線ID
        /// </summary>
        [Key]
        public string ConnectionID { get; set; }

        /// <summary>
        /// 使用者名稱稱
        /// </summary>
        public string Name { get; set; }

        public User(string name, string connectionId)
        {
            this.Name = name;
            this.ConnectionID = connectionId;
        }
    }

    /// <summary>
    /// 點對點(一對一)聊天
    /// </summary>
    [HubName("chat")]
    public class OneToOneHub : Hub
    {
        public static List<User> users = new List<User>();

        //傳送訊息
        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);
                //給自己傳送,把使用者的ID傳給自己
                Clients.Client(Context.ConnectionId).addMessage(message + "" + DateTime.Now, connectionId);
            }
            else
            {
                Clients.Client(Context.ConnectionId).showMessage("該使用者已離線...");
            }
        }

        [HubMethodName("getName")]
        public void GetName(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();
        }

        /// <summary>
        /// 重寫連線事件
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            //查詢使用者
            var user = users.Where(u => u.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);
        }

        //獲取所有使用者線上列表
        private void GetUsers()
        {
            var list = users.Select(s => new { s.Name, s.ConnectionID }).ToList();
            string jsonList = JsonConvert.SerializeObject(list);
            Clients.All.getUsers(jsonList);
        }
    }
}

如果你是vs2015 的話新增的mvc專案 不進行身份驗證的那種吧,必須得新增一個Startup 類。如果沒有這個類請新增,不然的話專案執行不起來的,具體程式碼如下:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalROneToOneDemo.App_Start.SignalRQuickStart))]

namespace SignalROneToOneDemo.App_Start
{
    public class SignalRQuickStart
    {
        public void Configuration(IAppBuilder app)
        {
            // 有關如何配置應用程式的詳細資訊,請訪問 https://go.microsoft.com/fwlink/?LinkID=316888
            // 配置集線器
            app.MapSignalR();
        }
    }
}

2.4、一對一聊天前臺程式碼實現

@{
    ViewBag.Title = "OneToOneChat";
}

<h2>點對點(一對一)聊天例項程式碼</h2>

<div>
    <div>使用者名稱稱:<label id="userName"></label>(<label id="conId"></label>)</div>
    
    <div style="width:25%;border:1px solid #ff0000">
        <div>線上使用者列表</div>
        <ul id="users"></ul>
    </div>
    <div id="userBox">
    </div>
</div>

@section scripts {
    <script src="~/Scripts/jquery-3.3.1.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script type="text/javascript">
        var clients = [];
        var chat;
        $(function () {        
            chat = $.connection.chat;
            console.info(chat);

            //顯示提示方法
            chat.client.showMessage = function (message) {
                alert(message);
            }

            //註冊顯示資訊的方法
            chat.client.addMessage = function (message, connectionId) {
                //debugger
                if ($.inArray(connectionId, clients)==-1) {
                    showWin(connectionId);
                }
      
                $("#messages" + connectionId).each(function () {
                    $(this).append('<li>'+message+'</li>');
                })
            }

            //註冊顯示所有使用者的方法
            chat.client.getUsers = function (data) {            
                if (data) {
                    var json = $.parseJSON(data);                    
                    console.info(json);
                    $("#users").html(" ");
                    for (var i = 0; i < json.length; i++) {                        
                        var html = '<li>使用者名稱:' + json[i].Name + '<input type="button" connectionId="' + json[i].ConnectionID + '" id="'  + json[i].ConnectionID + '" value="聊天"  onclick="userChat(this)" />' ;
                        $("#users").append(html);
                    }
                }
            }

            //註冊顯示推出聊天提示的方法
            chat.client.exitUser = function (data)
            {
                alert(data);
            }

            //註冊顯示個人資訊的方法
            chat.client.showId = function (data)
            {
                $("#conId").html(data);
                clients.push(data);
            }

            //獲取使用者名稱稱
            $('#userName').html(prompt('請輸入您的名稱', ''));
 
            //連線成功後獲取自己的資訊
            $.connection.hub.start().done(function () {
                chat.server.getName($('#userName').html());
            });
        });

        //開始聊天
        function userChat(obj)
        {
            var connectionId = $(obj).attr('connectionId');
            showWin(connectionId);
        }

        function showWin(connectionId)
        { 
            clients.push(connectionId);
            var html = '<div style="float:left;margin-top:5px;margin-right: 5px;margin-bottom: 5px;border:1px solid #ff0000" id="' + connectionId + '" connectionId="' + connectionId + '">' + connectionId + '"的房間聊天記錄如下:<button onclick="exitChat(this)">退出</button><ul id="messages' + connectionId + '"></ul><input type="text" /> <button onclick="sendMessage(this)">傳送</button></div>';
            $("#userBox").append(html);
        }

        function exitChat(btnObj)
        {          
            $(btnObj).parent().remove();
            chat.server.exitChat(connectionId);
        }

        //傳送訊息
        function sendMessage(data)
        {
            var message = $(data).prev().val();
            var  userObj = $(data).parent();
            var username = $("#userName").html();
            message = username + ":" + message;
            console.info($(userObj).attr("connectionId"));
            var targetConnectionId = $(userObj).attr("connectionId");
            chat.server.sendMessage(targetConnectionId, message);
            $(data).prev().val("");
        }
    </script>
}

3、效果展示

到此,一個SignalR一對一(點對點)聊天例子就完成了,下面我們簡單的對程式碼作下分析:

Clients.Client(connectionId).addMessage():作用客戶端註冊addMessage方法,向指定連線Id的客戶端傳送訊息。由於一對一聊天傳送的訊息也應該回發給自己,所以回發給自己連線的Id可以通過Context.ConnectionId來獲取。當然也也可以使用Client.Caller()代替Client.Client(Context.ConnectionId)方法直接傳送。

Client.Clients(IList connectionIds):同時向多個ConnectionId傳送訊息,類似於QQ上@好友的功能。

通過瀏覽器F12我們可以看到SignalR給我們生成的方法:

可以看到我們服務端開發的兩個方法,需要特別說明的是伺服器端的方法名在客戶端呼叫都約定第一個字母為小寫,當然我們也可以通過方法名上加特性HubMethodName進行標識處理。

4、程式碼下載

例項原始碼可以移步github下載,地址:https://github.com/yonghu86/SignalRTestProj

5、參考文章

  • RDIFramework.NET敏捷開發框架通過SignalR技術整合即時通訊(IM)

  • 史上最全面的SignalR系列教程-1、認識SignalR

  • 史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式

  • 史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式

  • 史上最全面的SignalR系列教程-4、SignalR 自託管全解(使用Self-Host)-附各終端詳細例項

  • 史上最全面的SignalR系列教程-目錄彙總

  • Real-time ASP.NET with SignalR

  • 微信公眾號開發系列-玩轉微信開發-目錄彙總

  • RDIFramework.NET — 基於.NET的快速資訊化系統開發框架 — 系列目錄

  • RDIFramework.NET ━ .NET快速資訊化系統開發框架 ━ 工作流程元件介紹

  • RDIFramework.NET框架SOA解決方案(集Windows服務、WinForm形式與IIS形式釋出)-分散式應用

  • RDIFramework.NET程式碼生成器全新V3.5版本釋出-重大升級


一路走來數個年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址瞭解詳情。

RDIFramework.NET官方網站:http://www.rdiframework.net/

RDIFramework.NET官方部落格:http://blog.rdiframework.net/

同時需要說明的,以後的所有技術文章以官方網站為準,歡迎大家收藏!

RDIFramework.NET框架由海南國思軟體科技有限公司專業團隊長期打造、一直在更新、一直在升級,請放心使用!

歡迎關注RDIFramework.net框架官方公眾微信(微訊號:guosisoft),及時瞭解最新動態。

掃描二維碼立即關注

相關推薦

全面的SignalR系列教程-5SignalR 實現一對一聊天

1、概述 通過前面幾篇文章 史上最全面的SignalR系列教程-1、認識SignalR 史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式 史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式 史上最全面的SignalR系列教程-4、Si

全面的SignalR系列教程-2SignalR 實現推送功能-永久連線類實現方式

1、概述 通過上篇史上最全面的SignalR系列教程-1、認識SignalR文章的介紹,我們對SignalR技術已經有了一個全面的瞭解。本篇開始就通過SignalR的典型應用的實現方式做介紹,例子雖然簡單,但麻雀雖小五臟俱全。可以以此為基礎,擴充套件到實際應用中。 SignalR 的實現機制與.NET WCF

全面的SignalR系列教程-3SignalR 實現推送功能-集線器類實現方式

1、概述 通過前兩篇 史上最全面的SignalR系列教程-1、認識SignalR 史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式 文章對SignalR的介紹,我們對SignalR已經有了全面的認識。SignalR API 客戶端和伺服器端持久連線的通訊方式,一次連線代

全面的SignalR系列教程-4SignalR 自託管全解(使用Self-Host)-附各終端詳細例項

1、概述 通過前面幾篇文章 史上最全面的SignalR系列教程-1、認識SignalR 史上最全面的SignalR系列教程-2、SignalR 實現推送功能-永久連線類實現方式 史上最全面的SignalR系列教程-3、SignalR 實現推送功能-集線器類實現方式 我們對SignalR的概念以及SignalR

全面的SignalR系列教程-6SignalR 實現聊天

1、概述 通過前面幾篇文章對SignalR的詳細介紹。我們知道Asp.net SignalR是微軟為實現實時通訊的一個類庫。一般情況下,SignalR會使用JavaScript的長輪詢(long polling)的方式來實現客戶端和伺服器通訊,隨著Html5中WebSockets出現,SignalR也支援We

全面的SignalR系列教程-1認識SignalR

SignalR 是什麼? SignalR 是一個面向 ASP.NET 開發人員的庫,可簡化將實時 web 功能新增到應用程式的過程。 實時 web 功能是讓伺服器程式碼將內容推送到連線的客戶端立即可用,而不是讓伺服器等待客戶端請求新資料的能力。 SignalR 是一個整合的客戶端與伺服器庫,基於瀏覽器的客戶端

簡單的MySQL教程系列分享專欄

《史上最簡單的MySQL教程》系列分享專欄 《史上最簡單的MySQL教程》已整理成PDF文件,點選可直接下載至本地查閱https://www.webfalse.com/read/207399.html 簡介 整理史上最簡單的MySQL教程,來自csdn的推薦專欄,博主從入門到進階,詳細講

2018最新全面SpringBoot教程

pring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力於在蓬勃發展的快速應用開發領域(rapid application

2019最新全面SpringBoot教程

Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力於在蓬勃發展的快速應用開發領域(rapid applicatio

Vue2.0全入坑教程(下)—— 實戰案例

多少 跳轉 border src fff end har second vue 前言:經過前兩節的學習,我們已經可以創建一個vue工程了。下面我們將一起來學習制作一個簡單的實戰案例。 說明:默認我們已經用vue-cli(vue腳手架或稱前端自動化構建工具)創建好項目了 一

簡單的 SpringCloud 教程 | 終章

conf con 知識 實例 feign 地址 聚合 com red 版權聲明:本文為博主原創文章,歡迎轉載,轉載請註明作者、原文超鏈接 ,博主地址:http://blog.csdn.net/forezp。 目錄(?)[+] 轉載請標明出處: http

簡單的 SpringCloud 教程 | 第十四篇: 服務註冊(consul)

配置 資料 源碼下載 擴展性 local sta tar value mark 這篇文章主要介紹 spring cloud consul 組件,它是一個提供服務發現和配置的工具。consul具有分布式、高可用、高擴展性。 consul 具有以下性質: 服務發現:cons

簡單的SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config)(Finchley版本)

prope shu 由於 ext master strip div 文件配置 rap 在上一篇文章講述zuul的時候,已經提到過,使用配置服務來保存各個服務的配置文件。它就是Spring Cloud Config。 在分布式系統中,由於服務數量巨多,為了方便服務配置文件統

簡單的SpringCloud教程 | 第五篇: 路由網關(zuul)(Finchley版本)

開頭 proxy 打開 系統 blog 註冊 hub 需要 ews 在微服務架構中,需要幾個基礎的服務治理組件,包括服務註冊與發現、服務消費、負載均衡、斷路器、智能路由、配置管理等,由這幾個基礎組件相互協作,共同組建了一個簡單的微服務系統。一個簡答的微服務系統如下圖: 註

簡單的SpringCloud教程 | 第五篇: 路由網關(zuul)

under 中心 sig ribbon 請求 安全 src htm span 在微服務架構中,需要幾個基礎的服務治理組件,包括服務註冊與發現、服務消費、負載均衡、斷路器、智能路由、配置管理等,由這幾個基礎組件相互協作,共同組建了一個簡單的微服務系統。一個簡答的微服務系統如

簡單的SpringCloud教程 | 第二篇: 服務消費者(rest+ribbon)

image tree 開啟 then rom cat learn 替代 官網 最新Finchley版本:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f2-ribbon/或者http://blog.csdn.n

簡單的 SpringCloud 教程 | 第一篇: 服務的註冊與發現(Eureka)

add 過程 sdn 需要 2.3 boot one ini tail 最新Finchley版本請訪問:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f1-eureka/或者http://blog.csdn.n

簡單的SpringCloud教程 | 第十三篇: 斷路器聚合監控(Hystrix Turbine)

打開 jsb cli fill alt 數據 需要 eap south 當我們有很多個服務的時候,這就需要聚合所以服務的Hystrix Dashboard的數據了。這就需要用到Spring Cloud的另一個組件了,即Hystrix Turbine。 看單個的Hystri

簡單的SpringCloud教程 | 第十二篇: 斷路器監控(Hystrix Dashboard)

詳細 pre 良好的 依次 alt ews 需要 ext 數據監控 最新Finchley版本,請訪問:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f12-dash/或者http://blog.csdn.net

簡單的SpringCloud教程 | 第四篇:斷路器(Hystrix)

技術分享 熔斷器 enable layer get local nsh 12c host 在微服務架構中,根據業務來拆分成一個個的服務,服務與服務之間可以相互調用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign來調用。為了保證