SignalRMvc的简单例子
1.介绍
我们知道传统的http采用的是“拉模型”,也就是每次请求,每次断开这种短请求模式,这种场景下,client是老大,server就像一个小乌龟任人摆布,
很显然,只有一方主动,这事情就没那么完美了,所以为了能够让server也能主动点,html5就应运而生了,或许大家都知道html5中有两种server的主动
模型,第一种叫做websockect,也就是基于tcp模式的双工通讯,还有一种叫做SSE,也就是客户端来订阅服务器的一种事件模型,当然了,在html5出
来之前,如果要做到服务器主动,我们只能采用变相的longpool和foreverframe勉强实现,而signalR这吊毛就是一个对他们进行了高层封装,也就是说
signalR会在这四种技术中根据浏览器和服务器设置采取最优的一种模式,废话不多说,我们快速建立一个例子。
2.快速搭建
1.引入dll

2.创建hub类(消息处理)
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Web; namespace SignalRMvcDemo
{
[HubName("MessageHub")]
public class MessageHub : Hub
{
//当前用户
public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表
RedisClient client = new RedisClient("192.168.10.134", , "", ); /// <summary>
/// 登录连线
/// </summary>
/// <param name="userId">用户Id</param>
/// <param name="userName">用户名</param>
public void Register(string userName)
{
OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
var connnectId = Context.ConnectionId;
if (!OnlineUsers.Any(x => x.ConnectionId == connnectId))
{
//添加在线人员
OnlineUsers.Add(new UserInfo
{
ConnectionId = connnectId,
UserName = userName,
LastLoginTime = DateTime.Now
});
}
// 所有客户端同步在线用户
Clients.All.onConnected(connnectId, userName, OnlineUsers);
client.Set<List<UserInfo>>("list", OnlineUsers);
} /// <summary>
/// 发送私聊
/// </summary>
/// <param name="toUserId">接收方用户ID</param>
/// <param name="message">内容</param>
public void SendPrivateMessage(string toConnectionId, string message)
{
OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
var fromConnectionId = Context.ConnectionId; var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toConnectionId);
var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromConnectionId); if (toUser != null)
{
Clients.Client(toUser.ConnectionId).receivePrivateMessage(fromUser.ConnectionId, fromUser.UserName, message);
}
else
{
//表示对方不在线
Clients.Caller.absentSubscriber();
}
} /// <summary>
/// 全部发送
/// </summary>
/// <param name="message"></param>
public void AllSend(string name, string message)
{
Clients.All.AllSend(name, message);
} /// <summary>
/// 连线时调用
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
//Console.WriteLine("客户端连接,连接ID是:{0},当前在线人数为{1}", Context.ConnectionId, OnlineUsers.Count + 1);
return base.OnConnected();
} /// <summary>
/// 断线时调用
/// </summary>
/// <param name="stopCalled"></param>
/// <returns></returns>
public override Task OnDisconnected(bool stopCalled)
{
OnlineUsers = client.Get<List<UserInfo>>("list")??new List<UserInfo>();
var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId); // 判断用户是否存在,存在则删除
if (user == null)
{
return base.OnDisconnected(stopCalled);
}
// 删除用户
OnlineUsers.Remove(user);
Clients.All.onUserDisconnected(OnlineUsers); //调用客户端用户离线通知
client.Set<List<UserInfo>>("list", OnlineUsers); return base.OnDisconnected(stopCalled);
} /// <summary>
/// 重新连接时调用
/// </summary>
/// <returns></returns>
public override Task OnReconnected()
{
return base.OnReconnected();
}
} public class UserInfo
{
public string ConnectionId { get; set; }
public string UserName { get; set; }
public DateTime LastLoginTime { get; set; }
}
}
3.Startup类(1.配置跨域 2.配置多实例)
using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors; [assembly: OwinStartup(typeof(SignalRMvcDemo.StartupSignalR))] namespace SignalRMvcDemo
{
public class StartupSignalR
{
public void Configuration(IAppBuilder app)
{
//允许CORS跨域
app.UseCors(CorsOptions.AllowAll);
#region Redis配置
//添加redis
RedisScaleoutConfiguration redisScaleoutConfiguration = new RedisScaleoutConfiguration("192.168.10.134", , "", "redis_signalr");
//连接DB,默认为0
redisScaleoutConfiguration.Database = ;
//SignalR用Redis
GlobalHost.DependencyResolver.UseRedis(redisScaleoutConfiguration);
#endregion
// 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR();//启动SignalR
}
}
}
4.前端调用(引用hub生产的js文件,前端方法名称要与后端一致)
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<meta charset="utf-8" />
<link href="Content/bootstrap.min.css" rel="stylesheet" />
<link href="Lib/toastr/toastr.min.css" rel="stylesheet" />
</head>
<body>
<div class="panel panel-default">
<div class="panel-body">
<h1>分布式-消息推送测试</h1>
</div>
</div>
<span>ConnectionId:</span>
<input type="text" id="ConnectionId" readonly value="">
<span>当前用户名称:</span>
<input type="text" id="UserName" readonly value="">
<hr>
<span>在线用户数量:</span>
<input type="text" id="userCount" readonly value="">
<hr>
<table class="table table-bordered">
<thead>
<tr>
<th>ConnectionId</th>
<th>UserName</th>
</tr>
</thead>
<tbody id="tbody1"></tbody>
</table>
<span>接收用户:</span><select id="toUser"></select>
<input type="text" id="message" />
<input id="send" type="button" value="发送" />
<input id="sendAll" type="button" value="发送消息(所有客户端)" />
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Lib/toastr/toastr.min.js"></script>
<script src="Lib/iNotify/iNotify.js"></script>
<script src="Scripts/bootstrap.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<script src='/SignalR/hubs'></script>
<script type='text/javascript'>
$(function () {
$.connection.hub.url = 'http://localhost:10086/signalr';
//引用自动生成的代理,MessageHub是HubName注解属性
var work = $.connection.MessageHub; //对应后端的SendPrivateMessage函数,消息接收函数
work.client.receivePrivateMessage = function (connectionId, user, message) {
//$('#messgaeInfo').append(message + '</br>');
toastr.info('发送内容:' + message, "发送人:" + user)
Notify.player();
Notify.setTitle(true);
Notify.setTitle('你有新的消息!');
}; //对应后端的SendMessage函数,消息接收函数
work.client.AllSend = function (name, message) {
toastr.info('发送内容:' + message, "群发消息发生人:" + name)
Notify.player();
Notify.setTitle(true);
Notify.setTitle('你有新的消息!');
}; //后端SendLogin调用后,产生的loginUser回调
work.client.onConnected = function (connnectId, userName, OnlineUsers) {
reloadUser(OnlineUsers);
};
work.client.onUserDisconnected = function (OnlineUsers) {
reloadUser(OnlineUsers);
};
//hub连接开启
$.connection.hub.start().done(function () {
$('#UserName').val(prompt('请输入昵称:', ''));
var username = $('#UserName').val();
$('#ConnectionId').val($.connection.MessageHub.connection.id);
//发送上线信息
work.server.register(username); //点击按钮,发送消息
$('#send').click(function () {
var friend = $('#toUser').val();
//调用后端函数,发送指定消息
work.server.sendPrivateMessage(friend, $("#message").val());
}); //点击按钮,发送消息
$('#sendAll').click(function () {
//调用后端函数,发送指定消息
work.server.allSend($('#UserName').val(), $("#message").val());
});
});
}); //重新加载用户列表
var reloadUser = function (userlist) {
$("#tbody1").empty();
$("#toUser").empty();
$("#userCount").val(userlist.length);
for (i = 0; i < userlist.length; i++) {
$("#tbody1").append("<tr><td>" + userlist[i].ConnectionId + "</td><td>" + userlist[i].UserName + "</td></tr>");
$("#toUser").append("<option value=" + userlist[i].ConnectionId + ">" + userlist[i].ConnectionId + ':[' + userlist[i].UserName + "]</option>");
}
} //toastr配置
toastr.options = {
closeButton: true,
debug: false,
progressBar: true,
positionClass: "toast-bottom-right",
onclick: null,
showDuration: "300",
hideDuration: "1000",
timeOut: "5000",
extendedTimeOut: "1000",
showEasing: "swing",
hideEasing: "linear",
showMethod: "fadeIn",
hideMethod: "fadeOut"
}; //iNotify配置
var Notify = new iNotify({
audio: {
file: ['Sound/msg.mp3']
},
});
</script>
</body>
</html>
5.效果(支持跨域,需要有redis)


3.项目下载路径 https://github.com/lgxlsm/SignalRMvcDemo
SignalRMvc的简单例子的更多相关文章
- Hibernate4.2.4入门(一)——环境搭建和简单例子
一.前言 发下牢骚,这段时间要做项目,又要学框架,搞得都没时间写笔记,但是觉得这知识学过还是要记录下.进入主题了 1.1.Hibernate简介 什么是Hibernate?Hibernate有什么用? ...
- AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答
一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...
- spring mvc(注解)上传文件的简单例子
spring mvc(注解)上传文件的简单例子,这有几个需要注意的地方1.form的enctype=”multipart/form-data” 这个是上传文件必须的2.applicationConte ...
- ko 简单例子
Knockout是在下面三个核心功能是建立起来的: 监控属性(Observables)和依赖跟踪(Dependency tracking) 声明式绑定(Declarative bindings) 模板 ...
- mysql定时任务简单例子
mysql定时任务简单例子 ? 1 2 3 4 5 6 7 8 9 如果要每30秒执行以下语句: [sql] update userinfo set endtime = now() WHE ...
- java socket编程开发简单例子 与 nio非阻塞通道
基本socket编程 1.以下只是简单例子,没有用多线程处理,只能一发一收(由于scan.nextLine()线程会进入等待状态),使用时可以根据具体项目功能进行优化处理 2.以下代码使用了1.8新特 ...
- 一个简单例子:贫血模型or领域模型
转:一个简单例子:贫血模型or领域模型 贫血模型 我们首先用贫血模型来实现.所谓贫血模型就是模型对象之间存在完整的关联(可能存在多余的关联),但是对象除了get和set方外外几乎就没有其它的方法,整个 ...
- [转] 3个学习Socket编程的简单例子:TCP Server/Client, Select
以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计 ...
- jsonp的简单例子
jsonp的简单例子 index.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...
随机推荐
- MySQL索引调优【转】
一.关于查询计划 其实,关于所有的关系型数据库中,在运行T-SQL语句的时候,在查询器进行编译运行的同时,都会有着自己的内部的一个优化过程,而这优化之后的产物就是:执行计划. 在SQL SERVER中 ...
- 抢红包时用到的redis函数
2018-2-8 10:25:11 星期四 抢红包时经常会用redis(等其他nosql)的原子性函数去限流, 防止抢超, 下边列出一些主要的原子性函数 限制每个人只能抢一次 getSet(): 设置 ...
- 快速解决PHP调用Word组件DCOM权限的问题
1. 首先必须要在电脑上安装 Office 2. windows+r : 输入 dcomcnfg.exe 打开组件服务,然后双击 组件服务 ==> 双击 计算机 ==> 双击 我的电脑 = ...
- PHP程序守护进程化
一般Server程序都是运行在系统后台,这与普通的交互式命令行程序有很大的区别.glibc里有一个函数daemon.调用此函数,就可使当前进程脱离终端变成一个守护进程,具体内容参见man daemon ...
- ASP.NET MVC5高级编程 之 视图
1.1理解视图约定 当创建一个项目模版时,可以注意到,项目以一种非常具体的方式包含了一个结构化的Views目录.在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其对应.这就提供 ...
- Navicat系列产品激活教程
准备 本教程可破解12.x版本,如果教程失效请联系我 # 19.1.11 破解暂时失效,请勿更新 (如已更新请卸载重新安装老版本,数据不会丢失 http://download.navicat.com/ ...
- Codeforces 1110D Jongmah [DP]
洛谷 Codeforces 我-我我把这-这这题切了??? 说实话这题的确不难,只是我看到有大佬没做出来有点慌-- 突然发现这题是我在洛谷的第500个AC呢.那就更要写篇题解纪念一下了. 思路 容易想 ...
- 【进阶1-4期】JavaScript深入之带你走进内存机制(转)
这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://mp.weixin.qq.com/s/yK4DPKhkmkiroasWJMrJcw 阅读笔记 JS内存空间分为栈(stack).堆 ...
- Oracle SQL高级编程——分析函数(窗口函数)全面讲解
Oracle SQL高级编程--分析函数(窗口函数)全面讲解 注:本文来源于:<Oracle SQL高级编程--分析函数(窗口函数)全面讲解> 概述 分析函数是以一定的方法在一个与当前行相 ...
- Confluence 6 升级 Confluence 使用数据源
如果你对 Confluence 进行升级(手动或者使用安装器),你需要: 停止 Confluence (如果你已经尝试开始启动). 拷贝你的数据库驱动到 <installation-direct ...