一.应用场景: 在项目中有一个地方需要定时查询数据库是否有数据,如果有则显示在界面上。

二.可以使用ajax定时查询来做:

var inter = window.setInterval(refreshData,30000);   //每三十秒调用一次
function refreshData() {
$.ajax({
cache: false,
type: "POST",
url: "@(Url.Action("TJInfoData", "TJInfo"))",
success: function (data) {
if (data.code == "200") {
//alert(data.msg.Name);
//更新数据
}
else {
//alert(data.msg);
//无数据时,界面要清数据
//基本信息
$("#Lsh").text(""); }
},
error: function(xhr, ajaxOptions, thrownError) {
alert(thrownError);
}
});
}

三.ajax定时查询虽然简单明了,但是听说了signalr 后决定试下。

1. 添加包,nuget 搜索SignaR 安装即可。

2. 在前端页面添加js:

<!--Reference the SignalR library. -->
<script src="~/Scripts/jquery.signalR-2.2.2.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="~/signalr/hubs"></script>
<!--Reference the StockTicker script. -->
<script src="~/Scripts/TJDataQueryScript.js"></script>

其中 TJDataQueryScript.js 为利用signaR 进行通信的方法。

3. 首先创建路由:

using Microsoft.Owin;
using Owin; [assembly: OwinStartup(typeof(OfficialAgentWeb.SignalRHub.Startup))] namespace OfficialAgentWeb.SignalRHub
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
}

再创建连接器:

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Data.Domain;
using Data.Infrastructure;
using Data.Log4Net;
using Data.Services;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs; namespace OfficialAgentWeb.SignalRHub
{
[HubName("TJDataHubMini")]
public class TJDataHub : Hub
{
private readonly TJDataQuery _tjdata; public TJDataHub() : this(TJDataQuery.Instance) { } public TJDataHub(TJDataQuery stockTicker)
{
_tjdata = stockTicker;
} public override Task OnConnected()
{
var AdminId = Context.QueryString["AdminId"];
var YewuIsSuper = Context.QueryString["YewuIsSuper"];
WriteLog.Info("OnConnected: ConnectionId=" + Context.ConnectionId + ",AdminId="+ AdminId + ",YewuIsSuper=" + YewuIsSuper);
if (!_tjdata.ConnectIdAdminIdDic.ContainsKey(Context.ConnectionId))
{
_tjdata.ConnectIdAdminIdDic.Add(Context.ConnectionId, AdminId);
}
if (!_tjdata.ConnectIdIsSuperDic.ContainsKey(Context.ConnectionId))
{
_tjdata.ConnectIdIsSuperDic.Add(Context.ConnectionId, YewuIsSuper);
}
//
int adminIdInt = 0;
int.TryParse(AdminId, out adminIdInt);
bool YewuIsSuperBool = YewuIsSuper.ToLower().Equals("true") ? true : false;
var signalRConnectIdService = EngineContext.Current.Resolve<ISignalRConnectIdService>();
signalRConnectIdService.Insert(new M_SignalRConnectId { ConnectId = Context.ConnectionId, AdminId = adminIdInt, YewuIsSuper = YewuIsSuperBool, IsDeleted = false, IsActive = false }); return base.OnConnected();
} public override Task OnDisconnected(bool stopCalled)
{
var AdminId = Context.QueryString["AdminId"];
var YewuIsSuper = Context.QueryString["YewuIsSuper"];
WriteLog.Info("OnDisconnected: ConnectionId=" + Context.ConnectionId + ",AdminId="+ AdminId + ", YewuIsSuper=" + YewuIsSuper);
if (_tjdata.ConnectIdAdminIdDic.ContainsKey(Context.ConnectionId))
{
_tjdata.ConnectIdAdminIdDic.Remove(Context.ConnectionId);
}
if (_tjdata.ConnectIdIsSuperDic.ContainsKey(Context.ConnectionId))
{
_tjdata.ConnectIdIsSuperDic.Remove(Context.ConnectionId);
}
//
int adminIdInt = 0;
int.TryParse(AdminId, out adminIdInt);
var signalRConnectIdService = EngineContext.Current.Resolve<ISignalRConnectIdService>();
var cidQ = signalRConnectIdService.GetByConnectId(Context.ConnectionId);
if (cidQ != null)
{
var cidL = cidQ.ToList();
if (!(cidL == null || cidL.Count<1))
{
cidL.ForEach(p => p.IsDeleted = true);
signalRConnectIdService.Update(cidL);
}
} return base.OnDisconnected(stopCalled);
} public override Task OnReconnected()
{
var AdminId = Context.QueryString["AdminId"];
var YewuIsSuper = Context.QueryString["YewuIsSuper"];
WriteLog.Info("OnReconnected: ConnectionId=" + Context.ConnectionId + ",AdminId=" + AdminId + ",YewuIsSuper=" + YewuIsSuper);
if (!_tjdata.ConnectIdAdminIdDic.ContainsKey(Context.ConnectionId))
{
_tjdata.ConnectIdAdminIdDic.Add(Context.ConnectionId, AdminId);
}
if (!_tjdata.ConnectIdIsSuperDic.ContainsKey(Context.ConnectionId))
{
_tjdata.ConnectIdIsSuperDic.Add(Context.ConnectionId, YewuIsSuper);
}
//
int adminIdInt = 0;
int.TryParse(AdminId, out adminIdInt);
bool YewuIsSuperBool = YewuIsSuper.ToLower().Equals("true") ? true : false;
var signalRConnectIdService = EngineContext.Current.Resolve<ISignalRConnectIdService>();
signalRConnectIdService.Insert(new M_SignalRConnectId { ConnectId = Context.ConnectionId, AdminId = adminIdInt, YewuIsSuper = YewuIsSuperBool, IsDeleted = false, IsActive = false }); return base.OnReconnected();
} public IEnumerable<TJDataForTimer> GetAllStocks()
{
return null;
} [HubMethodName("NewContosoChatMessage")]
public void NewContosoChatMessage(string cid)
{
WriteLog.Info("TJDataQuery--IsAlive--cid=" + cid);
} }
}

创建一个单例来定时发布数据 给客户端:

using Bll.Admin;
using Data.Domain;
using Data.Infrastructure;
using Data.Log4Net;
using Data.Services;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using OfficialAgentWeb.Controllers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.SessionState; namespace OfficialAgentWeb.SignalRHub
{
public class TJDataQuery
{
// Singleton instance
private readonly static Lazy<TJDataQuery> _instance = new Lazy<TJDataQuery>(() => new TJDataQuery(GlobalHost.ConnectionManager.GetHubContext<TJDataHub>().Clients)); private readonly ConcurrentDictionary<string, TJDataForTimer> _stocks = new ConcurrentDictionary<string, TJDataForTimer>(); private readonly object _updateStockPricesLock = new object(); //stock can go up or down by a percentage of this factor on each change
private readonly double _rangePercent = .002; private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(30); //TimeSpan.FromMilliseconds(250);
private readonly Random _updateOrNotRandom = new Random(); //private readonly Timer _timer;
public Timer _timer { get; set; }
private volatile bool _updatingStockPrices = false; private TJDataQuery(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
ConnectIdAdminIdDic = new Dictionary<string, string>();
ConnectIdIsSuperDic = new Dictionary<string, string>(); _stocks.Clear(); _timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval); } public static TJDataQuery Instance
{
get
{
return _instance.Value;
}
} private IHubConnectionContext<dynamic> Clients
{
get;
set;
}
//ConnectId 和 AdminId 的字典
public Dictionary<string, string> ConnectIdAdminIdDic
{
get;
set;
}
//ConnectId 和 IsSuperDic 的字典
public Dictionary<string, string> ConnectIdIsSuperDic
{
get;
set;
} public IEnumerable<TJDataForTimer> GetAllStocks()
{
//return _stocks.Values;
return null;
} private void UpdateStockPrices(object state)
{
lock (_updateStockPricesLock)
{
if (!_updatingStockPrices)
{
_updatingStockPrices = true; //from database
var signalRConnectIdService = EngineContext.Current.Resolve<ISignalRConnectIdService>();
var cidQ = signalRConnectIdService.GetAllConnect();
if (cidQ != null)
{
var cidL = cidQ.ToList();
if (!(cidL == null || cidL.Count < 1))
{
//根据adminid查数据,然后分发推送到客户端。
Dictionary<int, List<string>> adminIdDic = new Dictionary<int, List<string>>();
foreach (var p in cidL)
{
if (!adminIdDic.ContainsKey(p.AdminId))
adminIdDic.Add(p.AdminId, new List<string> { p.ConnectId });
else
adminIdDic[p.AdminId].Add(p.ConnectId);
}
//
foreach (var a in adminIdDic)
{
var ayewu = false;
var cidL1 = cidL.Where(x => x.AdminId == a.Key).ToList();
if (!(cidL1 == null || cidL1.Count < 1))
{
ayewu = cidL1[0].YewuIsSuper;
}
var m = GetTJDataQuery(a.Key, ayewu);
//分发
foreach (var connectid in a.Value)
{
WriteLog.Info("BroadcastStockPrice begin: AdminId=" + a.Key + ",connectid="+ connectid);
BroadcastStockPrice(m, connectid);
}
} }
} //
Clients.All.IsAlive(); //foreach (var a in ConnectIdAdminIdDic)
//{
// var m = GetTJDataQuery(a.Value, a.Key);
// WriteLog.Info("BroadcastStockPrice begin: AdminId=" + a.Value);
// BroadcastStockPrice(m, a.Key);
//} _updatingStockPrices = false;
}
}
} private void BroadcastStockPrice(TJDataForTimer stock, string connectId)
{
if (stock == null || (!stock.code.Equals("200")))
{
WriteLog.Info("updateStockPrice begin: connectId=" + connectId + ", 推送空的内容");
}
else
{
WriteLog.Info("updateStockPrice begin: connectId=" + connectId + ", 推送了:" + (stock.msg == null ? "" : stock.msg.Name));
}
Clients.Client(connectId).updateStockPrice(stock);
//Clients.All.updateStockPrice(stock);
} private TJDataForTimer GetTJDataQuery(int AdminId, bool YewuIsSuperBool)
{
TJDataForTimer value = new TJDataForTimer();
B_TJInfo b = new B_TJInfo();
//int intAdmin = 0;
//int.TryParse(AdminId, out intAdmin);
//审核数量,待审核:0 今天已审核:0 今天审核通过:0 今天审核不通过:0
if (AdminId<1)
{
WriteLog.Info("GetTJDataQuery AdminId <0: AdminId=" + AdminId);
return null;
} count_sh count_Sh = b.GetCountSh(AdminId, YewuIsSuperBool);
if (count_Sh == null)
{ }
//
M_TJInfo m = b.GetNewSingle(AdminId, YewuIsSuperBool);
if (m == null)
{
WriteLog.Info("GetTJDataQuery GetNewSingle is null");
//return null;
value.code = "401";
value.msgCountsh = count_Sh;
return value;
}
//TJInfoDetail
List<M_TJInfoDetail> detailList = b.GetDetail(m.Id);
if (detailList == null || detailList.Count < 1)
{ } //MachineCheck
List<M_MachineCheck> machineList = b.GetMachine(m.OperateNo);
if (machineList == null || machineList.Count < 1)
{ } value.code = "200";
value.msg = m;
value.msgDetail = detailList;
value.msgMachine = machineList[0];
value.msgCountsh = count_Sh;
return value;
//return Json(new { code = "200", msg = m, msgDetail = detailList, msgMachine = machineList[0], msgCountsh = count_Sh });
} }
}

4. 运行时碰到的问题:

A. 客户端可以传递参数给服务器:

$.connection.hub.qs = { 'AdminId': $("#AdminIdHid").val(), 'YewuIsSuper': $("#YewuIsSuperHid").val()};

在服务端比如在OnConnected()里 使用 var AdminId = Context.QueryString["AdminId"]; 获取值。

B. 每次连接都会调用OnConnected()方法,失去连接会调用OnDisconnected 方法,由于超时等原因暂时连不上,然后又连上的调用OnReconnected重连,但是重连后connectId会变。

在OnConnected() 方法里把connectId 保存到数据库里。

在OnDisconnected 方法里 更新该connectId为失去连接。

但是在测试过程中,反复刷新该页面,也有可能出现某次OnDisconnected 没有调用的情况。

所有就会出现数据库里发现有3个connectId 在连接, 但是其实可能只有1个客户端在连接。

暂时想到的解决方法是:

服务端启动一个定时器每30分钟调用一次,调用客户端的方法,而客户端的方法是传递connectId到服务端的另外一个方法里。在服务器的该方法里可以根据connectId设置该客户端为活动状态。

服务器端创建一个任务Task,定时跑,查询连接表,如果发现该connectId 不是活动状态,则更新此数据。

代码:

Clients.All.IsAlive();

服务端调用客户端的IsAlive 方法。

然后客户端:

var ticker = $.connection.TJDataHubMini;

ticker.client.IsAlive = function () {
var clinetConectId = $.connection.hub.id+'';
console.log('clinetConectId=' + clinetConectId);
ticker.server.NewContosoChatMessage(clinetConectId).done(function () {
console.log('IsAliveService done');
});
}

客户端得到 ConectId 后调用服务端的 NewContosoChatMessage 的方法。

[HubMethodName("NewContosoChatMessage")]
public void NewContosoChatMessage(string cid)
{
WriteLog.Info("TJDataQuery--IsAlive--cid=" + cid);
}

可以在 此 NewContosoChatMessage 方法里更新数据表。

服务端创建任务参见另外一篇文章。

SignalR 的应用的更多相关文章

  1. SignalR系列续集[系列8:SignalR的性能监测与服务器的负载测试]

    目录 SignalR系列目录 前言 也是好久没写博客了,近期确实很忙,嗯..几个项目..头要炸..今天忙里偷闲.继续我们的小系列.. 先谢谢大家的支持.. 我们来聊聊SignalR的性能监测与服务器的 ...

  2. ABP文档 - SignalR 集成

    文档目录 本节内容: 简介 安装 服务端 客户端 连接确立 内置功能 通知 在线客户端 帕斯卡 vs 骆峰式 你的SignalR代码 简介 使用Abp.Web.SignalR nuget包,使基于应用 ...

  3. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

     SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...

  4. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...

  5. 基于SignalR实现B/S系统对windows服务运行状态的监测

    通常来讲一个BS项目肯定不止单独的一个BS应用,可能涉及到很多后台服务来支持BS的运行,特别是针对耗时较长的某些任务来说,Windows服务肯定是必不可少的,我们还需要利用B/S与windows服务进 ...

  6. SignalR SelfHost实时消息,集成到web中,实现服务器消息推送

    先前用过两次SignalR,但是中途有段时间没弄了,今天重新弄,发现已经忘得差不多了,做个笔记! 首先创建一个控制台项目Nuget添加引用联机搜索:Microsoft.AspNet.SignalR.S ...

  7. SignalR系列目录

    [置顶]用SignalR 2.0开发客服系统[系列1:实现群发通讯] [置顶]用SignalR 2.0开发客服系统[系列2:实现聊天室] [置顶]用SignalR 2.0开发客服系统[系列3:实现点对 ...

  8. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

  9. XAMARIN.ANDROID SIGNALR 实时消息接收发送示例

    SignalR 是一个开发实时 Web 应用的 .NET 类库,使用 SignalR 可以很容易的构建基于 ASP.NET 的实时 Web 应用.SignalR 支持多种服务器和客户端,可以 Host ...

  10. ABP源码分析三十二:ABP.SignalR

    Realtime Realtime是ABP底层模块提供的功能,用于管理在线用户.它是使用SignalR实现给在线用户发送通知的功能的前提 IOnlineClient/OnlineClient: 封装在 ...

随机推荐

  1. npm+react linux 开荒

    安装npm 从 https://nodejs.org/dist/ 找到下载包,并不是版本越高越好,得看项目的需要. 解压之后,将解压路径bin添加到PATH里. 完成后可配置npm源 npm inst ...

  2. Docker 架构演进之路

    转载:https://developer.aliyun.com/article/673009 前言 Docker已经推出了5年,在这5年中它极大的改变了互联网产品的架构,推进了新的产品开发.测试和运维 ...

  3. xml简单操作

    1.创建简单的XML 1 XmlDocument XmlDoc = new XmlDocument(); 2 //XML声明 3 var xmlDeclaration = XmlDoc.CreateX ...

  4. [Unity]自定义地图编辑器(Scene视图下,EditorWindow的简单应用)

    最近的游戏又很多关卡需要配置(XML保存),给策划写了个非常简单的编辑器,记录下+废话下 1:Editor下打开新窗口需要继承EditorWindow,然后使用获取窗口即可,注意放在Editor文件夹 ...

  5. 如何简化跨网络安全域的文件发送流程,大幅降低IT人员工作量?

    为什么要做安全域的隔离? 随着企业数字化转型的逐步深入,企业投入了大量资源进行信息系统建设,信息化程度日益提升.在这一过程中,企业也越来越重视核心数据资产的保护,数据资产的安全防护成为企业面临的重大挑 ...

  6. git提交到代码到远程仓库,合并分支提示entirely different commit histories(备忘)

    最近提交代码到github,合并分支的时候提示"master and main are entirely different commit histories" master为本地 ...

  7. 安装centos,ubuntu系统

    安装centos系统 1.首先进入VMware,新建虚拟机,选择典型,然后下一步 2.稍后安装系统,下一步 3.因为此次安装的是centos7.9系统,因此版本选择7 64位,下一步 4.选择虚拟机的 ...

  8. js判断任意数值接近数组中的某个值

    可以是数组,也可以是数组对象,看需求定义 let val = '' for (let i = 0; i < this.allData.length; i++) { if (this.days & ...

  9. #Cisco——配置链路聚合

    Cisco--配置链路聚合 一.什么是链路聚合. 链路聚合(英语:Link Aggregation)是一个计算机网络术语,指将多个物理端口汇聚在一起,形成一个逻辑端口,以实现出/入流量吞吐量在各成员端 ...

  10. docker 二进制安装

    首先所属环境为内网并且服务器拥有的开发环境不确定,需要跑当前服务所需代码,所以优先选择使用docker docker 文档地址 https://docs.docker.com 在 install 中存 ...