在上一章讲到了广播推送,即所有订阅的用户都能收到,这种适合于信息广播。

接下来介绍如何给指定的对象推送

在讲这个之前先说明一下连接创建的基础知识

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的对应关系,当然,实际项目中也可以用其他方式存储。

示例结果:

本章结束!

ASP.NET SignalR 系列(四)之指定对象推送的更多相关文章

  1. Asp.net SignalR 实现服务端消息实时推送到所有Web端

    ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.实际上 Asp.net SignalR 2 实现 服务端消息推送到Web端, 更加 ...

  2. 《ASP.NET SignalR系列》第四课 SignalR自托管(不用IIS)

    从现在开始相关文章请到: http://lko2o.com/moon 接着上一篇:<ASP.NET SignalR系列>第三课 SignalR的支持平台 一.概述 SignalR常常依托于 ...

  3. 《ASP.NET SignalR系列》第二课 SignalR的使用说明

    从现在开始相关文章请到: http://lko2o.com/moon 接续上一篇:<ASP.NET SignalR系列>第一课 认识SignalR (还没有看的话,建议您先看看) 一.指定 ...

  4. 《ASP.NET SignalR系列》第一课 认识SignalR

    从现在开始相关文章请到: http://lko2o.com/moon 一.概述 ASP.NET signalr对ASP.NET开发者来说是一个新的程序库,它能让我们更加容易便捷地开发实时通信功能; s ...

  5. 《ASP.NET SignalR系列》第五课 在MVC中使用SignalR

    接着上一篇:<ASP.NET SignalR系列>第四课 SignalR自托管(不用IIS) 一.概述 本教程主要阐释了如何在MVC下使用ASP.NET SignalR. 添加Signal ...

  6. 《ASP.NET SignalR系列》第三课 SignalR的支持平台

    从现在开始相关文章请到: http://lko2o.com/moon 接着第二课:<ASP.NET SignalR系列>第二课 SignalR的使用说明 一.服务器系统要求 SignalR ...

  7. Xamarin.Forms学习系列之Android集成极光推送

    一般App都会有消息推送的功能,如果是原生安卓或者IOS集成消息推送很容易,各大推送平台都有相关的Sample,但是关于Xamarin.Forms的消息推送集成的资料非常少,下面就说下Xamarin. ...

  8. ASP.NET SignalR 系列(五)之群组推送

    在上一章介绍了 一对一推送的方式,这章重点介绍下群组推送和多人推送 群组主要就是用到了方法:Groups.Add(Context.ConnectionId, groupName); 将不同的连接id加 ...

  9. ASP.NET SignalR 系列(八)之跨域推送

    前面几章讲的都是同域下的推送和订阅.这种讲讲如何跨域 对于SignalR来说,默认是不允许跨域的,因为安全问题.虽如此,但同时提供了跨域方案. 两种跨域方式: 1:JSONP2:CORS JSONP的 ...

随机推荐

  1. [原创]App弱网测试方法介绍

    [原创]App弱网测试方法介绍 1 什么是弱网? 弱网就是在非正常网络状态下,用户在访问网络时遭遇到网络延迟或是丢包,造成使用产品时用户体验不佳或反感的场景. 2   为什么要进行弱网测试 简而方之, ...

  2. C#控制台程序入口函数 Main(string[] args) 参数详解

    学习C#编程最常见的示例程序是在控制台应用程序中输出Hello World! using System; namespace DemoMainArgs { class Program { static ...

  3. Spring Cloud Ribbon源码分析---负载均衡实现

    上一篇结合 Eureka 和 Ribbon 搭建了服务注册中心,利用Ribbon实现了可配置负载均衡的服务调用.这一篇我们来分析Ribbon实现负载均衡的过程. 从 @LoadBalanced入手 还 ...

  4. 颜色空间模型(HSV\LAB\RGB\CMYK)

    通过Photoshop的拾色器,我们知道表征颜色的模型的不止一种,本文将系统并且详细讨论这四种模型(HSV.LAB.RGB和CMYK)之间的联系以及应用.本文部分章节整合了多位优秀博主的博客(链接见本 ...

  5. Unity资源商店 Asset store下载文件夹的位置

    Win10 C:\Users\用户名\AppData\Roaming\Unity\Asset Store-5.x\ Mac OS X ~/Library/Unity/Asset Store

  6. Java NIO 文件通道使用

    读取一个文件的内容,然后写入另外一个文件 public class NioTest4 { public static void main(String[] args) throws Exception ...

  7. 直接从ADB接出串口调试

    1,从硬件接出串口线 2,用串口工具连接上串口工具,串口工具地址:https://files.cnblogs.com/files/senior-engineer/%E4%B8%B2%E5%8F%A3% ...

  8. Xamarin.FormsShell基础教程(5)Shell项目内容新建页面

    Xamarin.FormsShell基础教程(5)Shell项目内容新建页面 轻拍内容列表页面中的Add按钮后,进入内容新建页面,如图1.4和图1.5所示.在该页面中,用户可以设置新建内容的标题和具体 ...

  9. Nginx实践篇(5)- Nginx代理服务 - 代理缓冲区、代理重新定义请求头、代理连接超时(转)

    Nginx实践篇(5)- Nginx代理服务 - 代理缓冲区.代理重新定义请求头.代理连接超时 nginx参数默认值 http://nginx.org/en/docs/http/ngx_http_co ...

  10. Raw image encoder error: Empty JPEG image (DNL not supported)) in throwOnEror

    OpenCV Error: Unknown error code -10 (Raw image encoder error: Empty JPEG image (DNL not supported)) ...