SignalR Self Host+MVC等多端消息推送服务(1)
一、概述
由于项目需要,最近公司项目里有个模块功能,需要使用到即时获得审批通知;原本的设计方案是使用ajax对服务器进行定时轮询查询,刚刚开始数据量和使用量不大的时候还好,后来使用量的增加和系统中各种业务的复杂度增加,服务器的压力也越来越大,于是我想使用消息推送的方式替换掉ajax轮询查询,当有审批提交时,调用推送方法,将消息推送到下一审批人那,这样就减低了服务器的压力。
SignalR是微软支持的一个运行在.NET平台上的 html websocket 框架。它出现的主要目的是实现服务器主动推送消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息。而且SignalR的兼容性也是很强大的,这里不在多言。既然选择了SignalR,那么就开始干吧!
我的想法是将SignalR做成一个自托管的服务,和我们的b/s项目分离出来,这样的好处是,1、推送服务不依赖于iis,就算iis挂了,我们的推送服务还可以正常运行;2、我们可以多平台调用这个推送服务,多个项目都可以同时使用;
二、创建服务端
废话不多说了,我也是第一次写博客,介绍完业务场景和构思,我们就开始撸码吧。
1、用VS创建一个名为 "SignalRProject" 的解决方案;

2、在 SignalRProject解决方案下新建一个名为Server的控制台

3、在程序包管理器控制台,输入如下命令
Install-Package Microsoft.AspNet.SignalR.SelfHost

4、输入如下命令:
Install-Package Microsoft.Owin.Cors

5、在Server控制台中添加UserInfo类,代码如下
using System; namespace Server
{
public class UserInfo
{
public string ConnectionId { get; set; }
public string UserName { get; set; }
public DateTime LastLoginTime { get; set; }
}
}

6、在Server控制台中添加ChatHub类,代码如下
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace Server
{
[HubName("IMHub")]
public class ChatHub : Hub
{
// 静态属性
public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表 /// <summary>
/// 登录连线
/// </summary>
/// <param name="userId">用户Id</param>
/// <param name="userName">用户名</param>
public void Register(string userName)
{
var connnectId = Context.ConnectionId; if (OnlineUsers.Count(x => x.ConnectionId == connnectId) == )
{
if (OnlineUsers.Any(x => x.UserName == userName))
{
var items = OnlineUsers.Where(x => x.UserName == userName).ToList();
foreach (var item in items)
{
Clients.AllExcept(connnectId).onUserDisconnected(item.ConnectionId, item.UserName);
}
OnlineUsers.RemoveAll(x => x.UserName == userName);
} //添加在线人员
OnlineUsers.Add(new UserInfo
{
ConnectionId = connnectId,
UserName = userName,
LastLoginTime = DateTime.Now
});
} // 所有客户端同步在线用户
Clients.All.onConnected(connnectId, userName, OnlineUsers);
} /// <summary>
/// 发送私聊
/// </summary>
/// <param name="toUserId">接收方用户连接ID</param>
/// <param name="message">内容</param>
public void SendPrivateMessage(string toUserName, string message)
{
var fromConnectionId = Context.ConnectionId; var toUser = OnlineUsers.FirstOrDefault(x => x.UserName == toUserName);
var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromConnectionId); if (toUser != null )
{
Clients.Client(toUser.ConnectionId).receivePrivateMessage(fromUser.UserName, message);
Clients.Client(toUser.ConnectionId).receivePrivateMessage(message);
}
else
{
//表示对方不在线
Clients.Caller.absentSubscriber();
}
} public void Send(string name, string message)
{
//Clients.All { get; } // 代表所有客户端
//Clients.AllExcept(params string[] excludeConnectionIds); // 除了参数中的所有客户端
//Clients.Client(string connectionId); // 特定的客户端,这个方法也就是我们实现端对端聊天的关键
//Clients.Clients(IList<string> connectionIds); // 参数中的客户端
//Clients.Group(string groupName, params string[] excludeConnectionIds); // 指定客户端组,这个也是实现群聊的关键所在
//Clients.Groups(IList<string> groupNames, params string[] excludeConnectionIds);参数中的客户端组
//Clients.User(string userId); // 特定的用户
//Clients.Users(IList<string> userIds); // 参数中的用户 Console.WriteLine("ConnectionId:{0}, InvokeMethod:{1}", Context.ConnectionId, "Send");
Clients.All.addMessage(name, message);
} /// <summary>
/// 连线时调用
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
Console.WriteLine("客户端连接,连接ID是:{0},当前在线人数为{1}", Context.ConnectionId, OnlineUsers.Count+);
return base.OnConnected();
} /// <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);
Console.WriteLine("客户端断线,连接ID是:{0},当前在线人数为{1}", Context.ConnectionId, OnlineUsers.Count);
return base.OnDisconnected(stopCalled);
} public override Task OnReconnected()
{
return base.OnReconnected();
}
}
}

7、在Server控制台中添加Startup类,代码如下
using Microsoft.Owin.Cors;
using Owin; namespace Server
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
//允许CORS跨域
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
}

8、修改Server控制台中添加Program类,代码如下
using Microsoft.Owin.Hosting;
using System; namespace Server
{
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:10086";//设定 SignalR Hub Server 对外的接口
using (WebApp.Start<Startup>(url))//启动 SignalR Hub Server
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
}

9、F5运行起来
然后浏览器中访问http://localhost:10086/signalr/hubs
结果如下:

见上图内容就基本完成了,今天先讲到着,时间不早了,先休息了,后续有时间再将后面的文章补上
SignalR Self Host+MVC等多端消息推送服务(1)的更多相关文章
- SignalR Self Host+MVC等多端消息推送服务(2)
一.概述 上次的文章中我们简单的实现了SignalR自托管的服务端,今天我们来实现控制台程序调用SignalR服务端来实现推送信息,由于之前我们是打算做审批消息推送,所以我们的demo方向是做指定人发 ...
- SignalR Self Host+MVC等多端消息推送服务(3)
一.概述 最近项目确实太忙,而且身体也有点不舒服,慢性咽炎犯了,昨晚睡觉时喘不过气来,一直没休息好,也没什么时间写博客,今天朋友问我什么时候能出web端的消息发送的文章时,我还在忙着改项目的事,趁着中 ...
- SignalR Self Host+MVC等多端消息推送服务(4)
由于工作太忙,一直没时间更新博客,之前有很多朋友一直问我什么时候将后续的代码发上来,一直没时间,今天就长话短说,不写文章了,直接上demo,里面将正式项目中用到的一些敏感信息修改了,要使用的话下载后自 ...
- Asp.net SignalR 实现服务端消息推送到Web端
之前的文章介绍过Asp.net SignalR, ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信. 今天我 ...
- python 全栈开发,Day131(向app推送消息,玩具端消息推送)
先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.4.zip 注意:由于涉及到 ...
- SSE(Server-sent events)技术在web端消息推送和实时聊天中的使用
最近在公司闲着没事研究了几天,终于搞定了SSE从理论到实际应用,中间还是有一些坑的. 1.SSE简介 SSE(Server-sent events)翻译过来为:服务器发送事件.是基于http协议,和W ...
- 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)
1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...
- SSM项目使用GoEasy 实现web消息推送服务
一.背景 之前项目需要做一个推送功能,最开始我用websocket实现我的功能.使用websocket的好处是免费自主开发,但是有几个问题:1)浏览器的兼容问题,尤其是低版本的ie:2)因为是推送 ...
- 异步tcp通信——APM.Server 消息推送服务的实现
消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...
随机推荐
- Docker镜像的构成__Dockerfile
相比docker commit来说,Dockerfile的方法会更加自动化,更加方便快捷,而且功能也更强大.拿构建Nginx容器举例. 先创建一个目录 mkdir /opt/docker-file 进 ...
- FFmepg 如何在 window 上使用?
下载FFmepg官网库直接使用即可. avdevice.lib avcodec.lib avfilter.lib avformat.lib avutil.lib postproc.lib swresa ...
- nyoj234 吃土豆 01背包
思路:假设我们先只考虑一行,规则就是取了i处的土豆,每一个土豆有两种选择,拿与不拿,那么i-1和i+1处的土豆都不能再取,那么要求某一行的最大取值就用一次动态规划即可,dp(i)表示前i个土豆能取得的 ...
- URAL - 1153 Supercomputer 大数开方
题意:给定m,m = n * (n+1) / 2,计算n值. 思路:n = SQRT(m*2) 注意m很大,需要自己实现大数开方.我用的是自己写的大数模板:大数模板 AC代码 #include < ...
- 内置函数 -- bytes -- 字节码与字符串相互转换
说明: 1. 返回值为一个新的不可修改字节数组,每个数字元素都必须在0 - 255范围内,是bytearray函数的具有相同的行为,差别仅仅是返回的字节数组不可修改. 2. 当3个参数都不传的时候,返 ...
- eclipse hadoop1.2.0配置及wordcount运行
"error: failure to login"问题 http://www.cnblogs.com/xia520pi/archive/2012/05/20/2510723.htm ...
- tensorflow+入门笔记︱基本张量tensor理解与tensorflow运行结构
Gokula Krishnan Santhanam认为,大部分深度学习框架都包含以下五个核心组件: 张量(Tensor) 基于张量的各种操作 计算图(Computation Graph) 自动微分(A ...
- 3.3.1 Cache一致性的基本概念
PCI设备对可Cache的存储器空间进行DMA读写的操作的过程较为复杂,有关Cache一致性的话题可以独立成书.而不同的处理器系统使用的Cache Memory的层次结构和访问机制有较大的差异,这部分 ...
- 微信开源的Android热补丁框架 Tinker
前不久,微信开源了其Android热补丁框架Tinker,它的特别之处在于放在github.com/Tencent下面,是该账号下第一个正式的开源项目,可以看到腾讯对它的重视和认可. 早在6月份微信客 ...
- AVS、MPEG-2、H264标准文档
联合信源对AVS解码源码和相应的AVS码流.AVS码流太大,可以从http://cosoft.org.cn/projects/avsdec下载.解压avsdec_source.zip后,用VC6编译a ...