ASP.NET SignalR 系列(四)之指定對象推送


在上一章講到了廣播推送,即所有訂閱的用戶都能收到,這種適合於信息廣播。

接下來介紹如何給指定的對象推送

在講這個之前先說明一下連接創建的基礎知識

1、每個頁面與服務端創建連接並啟動時,這時服務端會產生一個connectionId作為與這個客戶端連接的唯一標識。

2、這個connectionId將作為服務端向指定客戶端推送的依據

3、同一個頁面刷新后ConnectionId一樣不變

4、這個connectionId是服務端自動生成的一個隨機數,無法變更。

 

一、只推送給自己

為了與之前的例子區分,我們分別在服務端DemoHub新建個發送給自己的方法

public class DemoHub : Hub
    {
        /// <summary>
        /// 示例
        /// </summary>
        /// <param name="content">廣播的內容</param>
        public void Hello(string content)
        {
            Clients.All.show(content); //調用了前端js上定義的hello方法
        }

        /// <summary>
        /// 推送給自己
        /// </summary>
        /// <param name="content"></param>
        public void CallSelf(string content)
        {
            Clients.Caller.show(content);
        }
    }

這里使用了Caller,而不是All,表示只推送給呼叫方,即自己。

前端腳本邏輯不變,只是多了一個發送給自己的按鈕的推送到服務端CallSelf事件而已。

      //定義推送
        $.connection.hub.start()
            .done(function () {
                $("#btn_sendCall").click(function () {
                    chat.server.callSelf($("#content").val());  //將客戶端的content內容發送到服務端
                    $("#content").val("");
                });
            });

 

結果:

 

 



我是在窗口2這邊發送的,第一條點擊“發送”按鈕,是廣播,兩個窗口都能收到;第二條點擊“發送給自己”,只有窗口2收到。

 

二、其他推送方式

其他推送方式對於客戶端(前端)來說不變,主要就是服務端推送對象改變而已

以下列出其他推送方式:

  • 所有連接的客戶端  
    Clients.All.show(content);

  • 僅調用的客戶端
    Clients.Caller.show(content);

  • 除調用客戶端之外的所有客戶端
    Clients.Others.show(content);

  • 特定的客戶端標識的連接 id
    Clients.Client(Context.ConnectionId).show(content);

  • 所有連接的客戶端除外指定客戶端,由連接 ID 標識
    Clients.AllExcept(connectionId1, connectionId2).show(content);

  • 指定組中的所有連接的客戶端
    Clients.Group(groupName).show(content);
  • 指定組中的所有連接的客戶端除外指定客戶端,由連接 ID 標識。
    Clients.Group(groupName, connectionId1, connectionId2).show(content);

  • 所有連接的客戶端指定組中除調用客戶端
    Clients.OthersInGroup(groupName).show(content);

  • 所有客戶端和組列表中的連接 Id
    Clients.Clients(ConnectionIds).show(content);

  • 組的列表。
    Clients.Groups(GroupIds).show(content);

  • 按名稱的用戶
    Clients.Client(username).show(content);  //這里的username我還沒理解是怎么創建的

  • (在 SignalR 2.1 中引入) 的用戶名稱的列表。
    Clients.Users(new string[] { "myUser", "myUser2" }).show(content)

 

三、說說ConnectionId

前面已經說到,每個連接的頁面都會產生不同的連接id,並且這個連接id是隨機產生,不能自定義的,那我們如何獲取呢

集線器中為我們提供了Context對象可以獲取到這個連接id,先看下面簡單的例子

     /// <summary>
        /// 返回每個連接的id
        /// </summary>
        public void ReturnConnectionId()
        {
            Clients.Caller.show(Context.ConnectionId);
        }

 

前端:

     //定義推送,返回各個客戶端連接
        $.connection.hub.start()
            .done(function () {
                $("#btn_sendConnectionId").click(function () {
                    chat.server.returnConnectionId();  //將客戶端的content內容發送到服務端
                });
            });

結果:

 

 

 從結果可以看出,分別點擊返回各自的id,返回了不同的id。這個就驗證了系統給每個調用端分配一個不相同的隨機ConnectionId。

那我們如何利用這個ConnnectionId來實現給某個客戶端發送消息,比如一對一的聊天。這個就需要我們實現將人與ConnectionId信息建立對應關系。

如,我們假設張三和李四一對一聊天,那怎么實現,張三發送李四的消息只有李四收到呢,反之,亦然。即我們需要分別確定張三和李四的ConnectionId,並將它們的ConnnectionId與張三、李四建立對應關系。

即建立以下的對應關系
張三   張三的ConnectionId
李四   李四的ConnectionId

張三和李四是已知的,那么就需要在張三和李四分別與集線器建立連接生成ConnenctionId時,我們就要實現對應關系的建立。

這時候需要重載建立連接的方法:

服務端:

     /// <summary>
        /// 發送給指定連接
        /// </summary>
        /// <param name="toName"></param>
        /// <param name="content"></param>
        public void CallOne(string toName,string content)
        {
            //根據username獲取對應的ConnectionId
            var connectionId = HttpContext.Current.Application[toName].ToString();
            Clients.Client(connectionId).show(content);
        }

        /// <summary>
        /// 初次連接
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected()
        {
            string username = Context.QueryString["userName"]; //獲取客戶端發送過來的用戶名
            string connectionId = Context.ConnectionId;
            HttpContext.Current.Application.Add(username,connectionId); //存儲關系
            return base.OnConnected();
        }

 

客戶端:建立zhangsan.html和lisi.html 分別表示張三和李四的窗口

zhangsan.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <link href="Content/bootstrap.min.css" rel="stylesheet" />
    <script src="Scripts/jquery-1.10.2.min.js"></script>
    <script src="Scripts/jquery.signalR-2.3.0.min.js"></script>
    <script src="/signalr/hub/hubs"></script>
    <meta charset="utf-8"/>
    <style type="text/css">
        body {
            margin: 20px;
        }
        .input {
            padding-left: 5px;
        }

    </style>
</head>
<body>
<div>
    <h4>我是張三</h4>
    <p>
        <input type="text" id="content" placeholder="" class="input"/> &nbsp;&nbsp;<input type="button" value="發送給李四" class="btn btn-sm btn-info" id="btn_send"/>
    </p>

    <div>
        <h4>接收到的信息:</h4>
        <ul id="dataContainer">

        </ul>
    </div>
</div>

<script language="javascript">
    $(function() {
        var chat = $.connection.demoHub; //連接服務端集線器,demoHub為服務端集線器名稱,js上首字母須改為小寫(系統默認)
        //定義客戶端方法,此客戶端方法必須與服務端集線器中的方法名稱、參數均一致。
        //實際上是服務端調用了前端的js方法(訂閱)

        $.connection.hub.qs = { 'userName': '張三' }
        chat.client.show=function(content) {
            var html = '<li>' + htmlEncode(content) + "</li>";
            $("#dataContainer").append(html);
        }

        //定義推送
        $.connection.hub.start()
            .done(function() {
                $("#btn_send").click(function() {
                    chat.server.callOne("李四",$("#content").val());  //將客戶端的content內容發送到服務端
                    $("#content").val("");
                });
            });
    });
    //編碼
    function htmlEncode(value) {
        var encodedValue = $('<div />').text(value).html();
        return encodedValue;
    }
</script>
</body>
</html>

 

lisi.html:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <link href="Content/bootstrap.min.css" rel="stylesheet" />
    <script src="Scripts/jquery-1.10.2.min.js"></script>
    <script src="Scripts/jquery.signalR-2.3.0.min.js"></script>
    <script src="/signalr/hub/hubs"></script>
    <meta charset="utf-8" />
    <style type="text/css">
        body {
            margin: 20px;
        }

        .input {
            padding-left: 5px;
        }
    </style>
</head>
<body>
    <div>
        <h4>我是李四</h4>
        <p>
            <input type="text" id="content" placeholder="" class="input" /> &nbsp;&nbsp;<input type="button" value="發送給張三" class="btn btn-sm btn-info" id="btn_send" />
        </p>

        <div>
            <h4>接收到的信息:</h4>
            <ul id="dataContainer"></ul>
        </div>
    </div>

    <script language="javascript">
    $(function() {
        var chat = $.connection.demoHub; //連接服務端集線器,demoHub為服務端集線器名稱,js上首字母須改為小寫(系統默認)
        //定義客戶端方法,此客戶端方法必須與服務端集線器中的方法名稱、參數均一致。
        //實際上是服務端調用了前端的js方法(訂閱)
        $.connection.hub.qs = { 'userName': '李四' }
        chat.client.show=function(content) {
            var html = '<li>' + htmlEncode(content) + "</li>";
            $("#dataContainer").append(html);
        }

        //定義推送
        $.connection.hub.start()
            .done(function() {
                $("#btn_send").click(function() {
                    chat.server.callOne("張三", $("#content").val());  //將客戶端的content內容發送到服務端
                    $("#content").val("");
                });
            });
    });
    //編碼
    function htmlEncode(value) {
        var encodedValue = $('<div />').text(value).html();
        return encodedValue;
    }
    </script>
</body>
</html>

 

說明:

1、參數傳遞的方法

 $.connection.hub.qs = { 'userName': '李四' }

2、后端獲取參數的方法:

Context.QueryString["username"]

3、本例中利用Application對象來存儲用戶與ConnectionId的對應關系,當然,實際項目中也可以用其他方式存儲。

示例結果:

 

本章結束!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM