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等技术实现,消息对列可使用 ...
随机推荐
- java打包项目将配置文件放在包外面(后续还会有补充)
项目中也经常单独将一部分功能独立做Java Project,然后打成jar包供其他项目调用.如果jar包中需要读取配置文件信息,则很少把该配置打进jar包,因为它不方便修改,更多都是采用jar包读取外 ...
- 解决maven项目Cannot change version of project facet Dynamic web module to 3.0
问题描述 用Eclipse创建Maven结构的web项目的时候选择了Artifact Id为maven-artchetype-webapp,由于这个catalog比较老,用的servl ...
- MySQL之表的数据类型
一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 详细参考: http://www.runoob.com/mysql/mysql-data ...
- Android安全机制
1)Android是基于Linux内核的,因此Linux对文件权限的控制同样适用于Android.在Android中每个应用都有自己的/data/data/包名文件夹,该文件夹只能该应用访问,而其他应 ...
- 单例模式,堆,BST,AVL树,红黑树
单例模式 第一种(懒汉,线程不安全): public class Singleton { private static Singleton instance; private Singleton () ...
- 集成电路883和883b有什么区别
根据用途,元器件的质量等级可分为:用于元器件生产控制.选择和采购的质量等级和用于电子设备可靠性预计的质量等级两类,两者有所区别,又相互联系. 用于元器件生产控制.选择和采购的质量等级 元器件的质量等级 ...
- Java中字符串的一些常见方法
1.Java中字符串的一些常见方法 /** * */ package com.you.model; /** * @author Administrator * @date 2014-02-24 */ ...
- eclipse怎么恢复原状
eclipse怎么恢复原状 今天,我在写JSP页面时,将eclipse缩小窗口,后来我准备恢复,但是窗口却变成下面的状态
- WebService之CXF注解之五(配置文件)
1.web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version=" ...
- Regex 正则替换指定范围全部字符串
1.正则替换字符-------------------------------------------------------------------------------------------- ...