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. SQL注入:显错注入

    SQL注入的本质 就是把用户输入的数据当做代码执行 注入条件 1.用户能控制输入 2.能够将程序原本执行的代码,拼接上用户输入的数据进行执行 例: http://www.xxx.com/new.php ...

  2. sqlalchemy(2)

    orm介绍 orm英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为 ...

  3. 04-numpy-笔记-transpose

    借鉴代码https://blog.csdn.net/xiongchengluo1129/article/details/79017142 吐槽一下CSDN的垃圾广告.. 这是转置,所以1维(向量)和2 ...

  4. JAVA并发-ReentrantReadWriteLock

    简介 读写锁维护着一对锁,一个读锁和一个写锁.通过分离读锁和写锁,使得并发性比一般的排他锁有了较大的提升:在同一时间可以允许多个读线程同时访问,但是在写线程访问时,所有读线程和写线程都会被阻塞. 读写 ...

  5. 人工智能头条(公开课笔记)+AI科技大本营——一拨微信公众号文章

    不错的 Tutorial: 从零到一学习计算机视觉:朋友圈爆款背后的计算机视觉技术与应用 | 公开课笔记 分享人 | 叶聪(腾讯云 AI 和大数据中心高级研发工程师) 整    理 | Leo 出   ...

  6. 学习:逆向PUSH越界/INT 68/反调试导致的程序

    自己根据shark恒老师的分析,总结一下: 一般反调试自动关闭程序利用的函数有: 1.CreateToolhelp32Snapshot 2.FindWindow 3.ExitProcess 4.Pos ...

  7. 成神之Java之路

    既然励志在java路上走的更远,那就必须了解java的路径.先看图 image.png 更加细化的细节如下 一: 编程基础 不管是C还是C++,不管是Java还是PHP,想成为一名合格的程序员,基本的 ...

  8. CSP2019题解

    CSP2019题解 格雷码 按照生成的规则模拟一下即可. 代码 括号树 看到括号匹配首先想到用栈,然后又在树上就可以想到可追溯化栈. 令\(a_i=1\)表示\(i\)号节点上的括号为(,否则为), ...

  9. Gogs配置(本地安装篇-Debian)

    知识储备: 用过MySQL等 了解Linux最基本的操作 git常用操作 关于ssh 本文参考:linux上安装gogs搭建个人仓库 下载 https://github.com/gogs/gogs/r ...

  10. 软件推荐【Windows】

    随时更新...链接为官网,自用保证安全(不信任可以把鼠标放在超链接上预览一下)        如有备注,下载链接均为最新(因为都是官方自动更新的下载链) 首先: 推荐一个软件管家(毕竟有时外网不稳定, ...