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

二.可以使用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. 使用树莓派PICO点灯

    使用树莓派PICO点灯树莓派PICO简介具体步骤方式①下载Thonny软件②为PICO烧录MicroPython固件①下载UF2文件②PICO进入boot模式烧录固件③进行点灯效果总结 具体步骤方式① ...

  2. CF207C

    前言 学习 zzd 博客( 这题超级没有素质. 连个题解都搜不到. 好不容易搜到一个. 看了一下是 pascal. 不过还好我有办法. 树剖做 \(k\) 级祖先. 十万的俩老哥飘过. 三百毫秒优异成 ...

  3. How to present a paper 怎么讲好一篇文献

    Author : 如果在冬夜一个旅人 Date : 2022/05/24 目录 背景说明 1 读文献 1.1 读文献的层次 1.2 论文阅读的首轮次序 2 讲文献 2.1 The Problem to ...

  4. Android FragmentTabHost底部选项卡实现

    记录一下底部选项卡的实现,很常见的代码,大神勿嘲笑. 说一下思路,在activity底部要放上FragmentTabHost放上选项,几个无所谓,每个选项卡都对应一个fragment,点击选项卡颜色改 ...

  5. 1414:【17NOIP普及组】成绩

    1414:[17NOIP普及组]成绩 时间限制: 1000 ms         内存限制: 65536 KB提交数: 27975     通过数: 17779 [题目描述] 牛牛最近学习了 C++入 ...

  6. 安装 deepin linux 系统、linux 使用记录

    安装 deepin 深度linux系统 官网:https://www.deepin.org/zh/ 包含了下载ios镜像和安装教程: 最新版本:https://www.deepin.org/zh/do ...

  7. vue、iview、VeeValidate 表单验证完整

    1.main.js (1).安装vee-validate npm install vee-validate --save (2).安装vue-i18n npm install vue-i18n --s ...

  8. LWC-002_Composition

    Composition (lwc.dev) Set a Property on a Child Component # Send an Event from a Child to an Owner   ...

  9. Linux-curl下载报错解决方法

    报错提示: curl: (92) HTTP/2 stream 1 was not closed cleanly before end of the underlying stream ==> E ...

  10. CH32F103C8T6调试口Disable后的修复办法

    1.问题描述 因为软件编程,将CH32F103的 debug disable了,无法通过仿真器下载程序. 2. 修复 2.1 解决思路 利用厂家给的串口ISP进行下载(HUSB或者COM) 2.2 硬 ...