一、概述

由于项目需要,最近公司项目里有个模块功能,需要使用到即时获得审批通知;原本的设计方案是使用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)的更多相关文章

  1. SignalR Self Host+MVC等多端消息推送服务(2)

    一.概述 上次的文章中我们简单的实现了SignalR自托管的服务端,今天我们来实现控制台程序调用SignalR服务端来实现推送信息,由于之前我们是打算做审批消息推送,所以我们的demo方向是做指定人发 ...

  2. SignalR Self Host+MVC等多端消息推送服务(3)

    一.概述 最近项目确实太忙,而且身体也有点不舒服,慢性咽炎犯了,昨晚睡觉时喘不过气来,一直没休息好,也没什么时间写博客,今天朋友问我什么时候能出web端的消息发送的文章时,我还在忙着改项目的事,趁着中 ...

  3. SignalR Self Host+MVC等多端消息推送服务(4)

    由于工作太忙,一直没时间更新博客,之前有很多朋友一直问我什么时候将后续的代码发上来,一直没时间,今天就长话短说,不写文章了,直接上demo,里面将正式项目中用到的一些敏感信息修改了,要使用的话下载后自 ...

  4. Asp.net SignalR 实现服务端消息推送到Web端

              之前的文章介绍过Asp.net SignalR,  ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.  今天我 ...

  5. python 全栈开发,Day131(向app推送消息,玩具端消息推送)

    先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.4.zip 注意:由于涉及到 ...

  6. SSE(Server-sent events)技术在web端消息推送和实时聊天中的使用

    最近在公司闲着没事研究了几天,终于搞定了SSE从理论到实际应用,中间还是有一些坑的. 1.SSE简介 SSE(Server-sent events)翻译过来为:服务器发送事件.是基于http协议,和W ...

  7. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

    1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...

  8. SSM项目使用GoEasy 实现web消息推送服务

      一.背景 之前项目需要做一个推送功能,最开始我用websocket实现我的功能.使用websocket的好处是免费自主开发,但是有几个问题:1)浏览器的兼容问题,尤其是低版本的ie:2)因为是推送 ...

  9. 异步tcp通信——APM.Server 消息推送服务的实现

    消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...

随机推荐

  1. java字符串以及字符类型基础

    介绍一下java字符集和字符的编码方式, 首先要区分一下字符集和字符编码.所谓的字符集 类似于unicode,GB2312,GBK,ASCII等等.因为一开始只有26个英文字母需要 编一下号.所有用下 ...

  2. Linux搭建FTP服务器

    一.搭建环境 阿里云 CentOS 7.3 64位 二.FTP协议基础知识 2.1 简介 FTP 是 File Transfer Protocol(文件传输协议)的英文简称,而中文简称为"文 ...

  3. WPF 照片墙的实现

    主要参照了DevExpress的PhotoGallery实例的实现. 效果如下: 照片墙核心代码如下: PhotoGallery.xaml <local:CarouselDemoModule x ...

  4. Java中的return关键字

    Java常见面试题之一: try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?  请看下面程序就可以解释 ...

  5. 笔记︱支持向量机SVM在金融风险欺诈中应用简述

    本笔记源于CDA-DSC课程,由常国珍老师主讲.该训练营第一期为风控主题,培训内容十分紧凑,非常好,推荐:CDA数据科学家训练营 欺诈一般不用什么深入的模型进行拟合,比较看重分析员对业务的了解,从异常 ...

  6. 判断一个jquery对象是否为空

    今天用jquery $获取一个jquery对象.$("#id") 然后用判断这个对象是否存在,id不存在的时候,判断这个是否存在, if($("#id")) 始 ...

  7. [Err] 1136 - Column count doesn't match value count at row 1

    1 错误描述 [Err] 1136 - Column count doesn't match value count at row 1 Procedure execution failed 1136 ...

  8. 如何利用JavaScript遍历JSON数组

    1.设计源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  9. iOS - Quartz 2D 下载进度按钮绘制

    1.绘制下载进度按钮 具体实现代码见 GitHub 源码 QExtension QProgressButton.h @interface QProgressButton : UIButton /// ...

  10. Log4j各级别日志重复打印

    使用filter进行日志过滤 这个其实是Log4j自带的方案,也是推荐方案,不知道为什么网上的资料却很少提到这点.把log4j.properties配置文件修改成如下: #root日志 log4j.r ...