Asp.net SignalR是微软为实现实时通信而开发的一个类库。可以适用于以下场景:

  • 聊天室,如在线客服系统,IM系统等
  • 股票价格实时更新
  • 消息的推送服务
  • 游戏中人物位置的实时推送

SignalR可以进行远程分布式实时通信,都是使用远程代理来实现,其中有两大内部对象,第一个是Persisten Connection,用于客户端和服务器端的持久连接,第二个是Hub(集线器)对象,主要用于信息交互,将服务器端的数据推送(push)至客户端,大致原理如下:

  1. 客户端建立与服务器端的连接
  2. 客户端调用服务器端的方法
  3. 服务器端通过客户端发送的请求,响应数据,调用客户端的方法将数据推送至客户端

4.1 SignalR的基本使用

接下来我们通过消息实时推送的案例来学习 SignalR 的使用步骤。具体操作步骤如下:

  1. 创建一个应用程序,我这里创建的是MVC应用程序
  2. 在MVC项目的Models文件夹中添加新项 SignalR集线器类。如图所示。

创建完成之后,在应用程序的Scripts文件夹里面会自动生成两个js文件,如图所示:

在创建的Hub类中添加如下代码:

//hub别名,方便前台调用

[HubName("getMsg")]

public class MyHub : Hub

{

public void Send(string title,string msg)

{

//调用客户端的sendMessage()方法

Clients.All.sendMessage(title,msg);

}

}

其中Clients.All是dynamic类型,sendMessaage()方法是视图中js定义的function。HubName特性用来给集线器类定义别名。

  1. 在项目中添加 OWIN StartUp 类。如图所示。

代码如下:

public class Startup

{

public void Configuration(IAppBuilder app)

{

//注册管道,使用默认的虚拟地址,根目录下的"/signalr",

//当然你也可以自己定义

app.MapSignalR();

}

}

  1. 创建控制器和视图

    创建MessageController,并创建两个用于显示视图的action。

控制器代码:

public class MessageController : Controller

{

//发送消息

public ActionResult SendMessage()

{

return View();

}

//接收消息

public ActionResult ReceiveMessage()

{

return View();

}

}

发送消息视图代码:

<h2>发送消息</h2>

<div>

标题:<input type="text" id="title" />

</div><br />

<div>

内容:<textarea id="message" rows="4" cols="30"></textarea>

</div>

<br />

<div>

<input type="button" id="sendmessage" value="发送" />

</div>

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

<!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->

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

<script type="text/javascript">

$(function () {

// 引用自动生成的集线器代理(此处使用别名getMsg)

var chat = $.connection.getMsg;

// 集成器连接开始

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

// 服务连接完成,给发送按钮注册单击事件

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

// 调用服务器端集线器的Send方法

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

});

});

});

</script>

接收消息视图代码:

<h2>接收消息</h2>

<div>

<br />

<div id="msgcontent"></div>

</div>

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

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

<script type="text/javascript">

$(function () {

// 引用自动生成的集线器代理

var chat = $.connection.getMsg;

// 定义服务器端调用的客户端sendMessage来显示新消息

chat.client.sendMessage = function (title, message) {

// 向页面发送接收的消息

var html = "<div>标题:" + title + "消息内容:" + message + "</div>";

$("#msgcontent").after(html);

};

// 集成器连接开始

$.connection.hub.start();

});

</script>

运行程序的时候,页面就与SignalR的服务建立了连接,具体的建立连接的代码就是:$.connection.hub.start()。这句代码的作用就是与SignalR服务建立连接,后面的done函数表明建立连接成功后为发送按钮注册了一个click事件,当客户端输入内容点击发送按钮后,该Click事件将会触发,触发执行的操作为: chat.server.send($("#title").val(), $('#message').val());。这句代码表示调用服务端的send函数,而服务端的Send方法又调用所有客户端的sendMessage函数,而客户端中sendMessage函数就是将信息添加到对应的消息列表中。这样就实现了广播消息的功能了。

在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,为了验证这一点,可以在Chrome中F12来查看源码就明白了,具体如下图所示:

看到上图,也就明白了为什么页面需要引入"signalr/hubs"脚本库了。

<!--引用SignalR库. -->

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

<!--引用自动生成的SignalR 集线器(Hub)脚本 -->

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

4.2 使用SignalR实现点对点聊天

介绍了群发消息的实现,下面来学习如何实现像QQ一样的点对点聊天。

Clients.All.sendMessage(title, message)表示调用所有客户端的SendMessage方法。除了All属性外,还具有其他属性,可以在VS中按F12来查看Clients对象的所有属性或方法,具体的定义如下:

public interface IHubConnectionContext<T>

{

T All { get; } // 代表所有客户端

T AllExcept(params string[] excludeConnectionIds); //除了参数中的所有客户端

T Client(string connectionId); // 特定的客户端,实现端对端聊天的关键

T Clients(IList<string> connectionIds); // 参数中的客户端

T Group(string groupName, params string[] excludeConnectionIds); // 指定客户端组,可以实现群聊

T Groups(IList<string> groupNames, params string[] excludeConnectionIds);

T User(string userId); // 特定的用户

T Users(IList<string> userIds); // 参数中的用户

}

  SignalR会每一个客户端分配一个ConnnectionId,这样我们就可以通过ConnnectionId来找到特定的客户端了。我们在向某个客户端发送消息的时候,除了要将消息传入,也需要将发送给对方的ConnectionId输入,这样服务端就能根据传入的ConnectionId来转发对应的消息给对应的客户端了。这样也就完成了端对端聊天的功能。另外,如果用户如果不在线的话,服务端可以把消息保存到数据库中,等对应的客户端上线的时候,再从数据库中查看该客户端是否有消息需要推送,有的话,从数据库取出数据,将该数据推送给该客户端。

下面我们来梳理下端对端聊天功能的实现思路:

  1. 客户端登入的时候记录下客户端的ConnnectionId,并将用户加入到一个静态数组中,该数据为了记录所有在线用户。
  2. 用户可以点击在线用户中的用户聊天,在发送消息的时候,需要将ConnectionId一并传入到服务端。
  3. 服务端根据传入的消息内容和ConnectionId调用Clients.Client(connnection).sendMessage方法来进行转发到对应的客户端。

根据上面的思路,先来实现集线器中的代码:

[HubName("Chat")]

public class ChatHub : Hub

{

// 静态属性,在线用户列表

public static List<UserInfo> OnlineUsers = new List<UserInfo>();

//登录

public void Login(string userId,string userName)

{

//获取客户端的ConnectionId

var connnectId = Context.ConnectionId;

OnlineUsers.Add(new UserInfo

{

ConnectionId = connnectId,

UserId = userId,

UserName = userName

});

// 所有客户端同步在线用户

Clients.All.loadUser(OnlineUsers);

}

/// <summary>

/// 发送私聊

/// </summary>

/// <param name="toUserId">接收方用户连接ID</param>

/// <param name="message">内容</param>

public void SendPrivateMessage(string toUserId, string message)

{

var fromUserId = Context.ConnectionId;

var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toUserId);

var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromUserId);

if (toUser != null && fromUser != null)

{

// 调用指定用户的客户端方法

Clients.Client(toUserId).receivePrivateMessage(fromUser.UserName, message);

}

else

{

//表示对方不在线

Clients.Caller.absentSubscriber();

}

}

/// <summary>

/// 断线时调用

/// </summary>

/// <param name="stopCalled"></param>

/// <returns></returns>

public override Task OnDisconnected(bool stopCalled)

{

var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);

// 判断用户是否存在,存在则删除

if (user == null) return base.OnDisconnected(stopCalled);

Clients.All.onUserDisconnected(user.ConnectionId, user.UserName); //调用客户端用户离线通知

// 删除用户

OnlineUsers.Remove(user);

return base.OnDisconnected(stopCalled);

}

}

客户端代码:

<h2>聊天系统</h2>

<div class="container">

@using (Html.BeginForm("login", "Chat", FormMethod.Post, new { @class = "form-inline" }))

{

<label>用户Id:</label>

@Html.TextBox("userId", "", new { @class = "form-control" })

<label>用户名:</label>

@Html.TextBox("userName", "", new { @class = "form-control" })

<input type="button" id="btnLogin" value="登录" class="btn btn-default" />

}

</div>

<hr />

<div class="container">

<div class="col-md-3">

<div class="panel panel-default">

<div class="panel-heading">

在线用户

</div>

<div class="panel-body">

<ul id="userList">

</ul>

</div>

</div>

</div>

<div class="col-md-8">

<div class="panel panel-default">

<div class="panel-heading">

聊天内容

</div>

<div class="panel-body">

<ul id="msgList" >

</ul>

</div>

<div class="panel-footer">

<label>消息To:</label> <label id="toUser"></label>

@Html.TextBox("msg", "", new { @class = "form-control form-inline" })

<input type="button" id="btnSend" value="发送" class="btn btn-default" />

</div>

</div>

</div>

</div>

@section scripts{

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

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

<script>

//用户点击(选择用户)

function selectUser(li) {

var connectionId = $(li).attr("cid");

$('#toUser').text(connectionId);

}

$(function () {

var chat = $.connection.Chat;

//刷新在线列表

chat.client.loadUser = function (allUsers) {

$('#userList').html("");

for (var i = 0; i < allUsers.length; i++) {

var li = $('<li cid="' + allUsers[i].ConnectionId+'" onclick="selectUser(this)">' + allUsers[i].UserId + ':' + allUsers[i].UserName + '</li> ');

$('#userList').append(li);

}

}

//接收消息

chat.client.receivePrivateMessage = function (from, msg) {

var li = $("<li>来自:" + from + "<br/>" + msg + "</li>");

$("#msgList").append(li);

}

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

console.log("连接完成");

//登录

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

chat.server.login($("#userId").val(), $('#userName').val())

})

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

chat.server.sendPrivateMessage($('#toUser').text(), $('#msg').val())

})

});

})

</script>

Asp.net MVC企业级开发(04)---SignalR消息推送的更多相关文章

  1. asp.net mvc 实现简单的实时消息推送

    因为项目需要,需要在网页上实现消息的推送.在百度上搜索了一下,发现实现网页上的消息推送,可以使用asp.net 中的SignalR类库,当然也可以使用H5的WebSocket  Ajax的轮回.当然此 ...

  2. WinForm中 Asp.Net Signalr消息推送测试实例

    p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...

  3. iOS开发如何实现消息推送机制

    一.关于推送通知 推送通知,也被叫做远程通知,是在iOS 3.0以后被引入的功能.是当程序没有启动或不在前台运行时,告诉用户有新消息的一种途径,是从外部服务器发送到应用程序上的.一般说来,当要显示消息 ...

  4. java开发微信模板消息推送

    发布时间:2018-12-12   技术:springboot+maven   概述 该demo主要涉及微信模板消息推送功能, 详细 代码下载:http://www.demodashi.com/dem ...

  5. 微信小程序开发:设置消息推送

    开发设置中,启用并设置消息推送配置后,用户发给小程序的消息以及开发者需要的事件推送,都将被微信转发至该服务器地址中. 不过照着说明去操作,即使按照最简单的明文方式去设置,还是提示Token验证失败.仔 ...

  6. Asp.net MVC企业级开发(01)---Autofac

    1.1 控制反转 在面向对象设计的软件系统中,它的底层都是由N个对象构成的,各个对象之间通过相互合作,最终实现系统的业务逻辑.同时,对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础.但是 ...

  7. signalR 消息推送

    业务情景一:上传报表,上传excel.如果excel的数据量很大,上万条,上十万条数据,那么这个上传请求必然是个耗时请求.用户上传之后,很关心上传的进度和结果. 业务情景二:站内消息提醒,实时有效地接 ...

  8. asp.net web 通过IHttpAsyncHandler接口进行消息推送

    .消息类,可直接通过这个类推送消息 HttpMessages using System; using System.Collections.Generic; using System.Linq; us ...

  9. Asp.net MVC企业级开发(02)---Log4net

    Log4Net 是用来记录日志的,可以将程序运行过程中的信息输出到一些地方(文件.数据库.EventLog等).日志就是程序的“黑匣子”,可以通过日志查看系统的运行过程,从而发现系统的问题. 日志的作 ...

随机推荐

  1. composer基本操作详解

    原文转自微信公众号:qq1005349393 Composer介绍 Composer 是 PHP 的一个包依赖管理工具.我们可以在项目中声明所依赖的外部工具库,Composer 会帮你安装这些依赖的库 ...

  2. odoo10学习笔记十:Actions

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/11189319.html actions定义了系统对于用户的操作的响应:登录.按钮.选择项目等. 一:窗口ac ...

  3. Ubuntu下部署Shipyard管理docker

    使用k8s对于我这种新人来说,难度有点大.遂尝试使用Shipyard这个docker web ui工具来进行管理,以方便入门. 首先,我们还是需要在我们的主机上安装docker. 然后官方提供了自动安 ...

  4. lf 前后端分离 (3) 中间建跨域

    一.关于中间建跨域 为了减少跨域代码冗余,采用中间件 from django.utils.deprecation import MiddlewareMixin class CorsMiddleware ...

  5. Celery详解(3)

    1.什么是Celery? Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统 专注于实时处理的异步任务队列,同时也支持任务调度 2.Celery架构 Celery的架构由三部分组成,消息中 ...

  6. Python查看帮助---help函数

    查看所有的关键字:help("keywords") 查看所有的modules:help("modules") 单看所有的modules中包含指定字符串的modu ...

  7. windows上传文件到 linux的hdfs

    一.windows上传文件到 linux的hdfs 1.先在 centos 上开启 hdfs, 用 jps 可以看到下面信息, 说明完成开启 2.在win上配置 hadoop (https://www ...

  8. OpenStack产品摘要

    docs OpenStack 核心服务 计算 Nova:虚拟化设施资源管理 ZUN:容器管理 QINLING:Serveless Function 裸金属 IRONIC:裸金属资源管理 CYBORDF ...

  9. JDOJ 1152 是否是素数

    1152: 是否是素数 https://neooj.com:8082/oldoj/problem.php?id=1152 题目描述 写一个判断素数的函数,在主函数输入一个整数,输出是否是素数的消息. ...

  10. Python进阶-XIV 面向对象初步

    1.面向对象的引入 def Person(*args): ''' 定义一个人 :param args: 人的属性 :return: 人的所有属性的字典 ''' info = {} info['name ...