SignalR SqlDependency Update 工作但在更改页面时它停止工作
SignalR SqlDependency Update work but when changing page it stops working
您好,感谢您阅读本文。
我用这个guide作为我的基础,我只添加了Owin Login/Registration(cookie)
当我登录时,它显示来自我的 NotificationHub 的通知,我能够更新数据库并立即运行更新。所以一切正常,直到您尝试切换页面,然后通知停止。即使我只是更新当前页面。
可能是什么问题?
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System.Security.Claims;
using System.Collections.Concurrent;
namespace LifeChange
{
[HubName("notificationHub")]
public class NotificationHub : Hub
{
private static readonly ConcurrentDictionary<string, User> Users = new ConcurrentDictionary<string, User>(StringComparer.InvariantCultureIgnoreCase);
private static List<User> UserList = new List<User>();
Int16 totalNewMessages = 0;
string UserID;
[HubMethodName("check")]
public Task Check(string id)
{
if (!Users.ToList().Exists(i => i.Value.ProfileId == id))
{
string profileId = id; //Context.QueryString["id"];
string connectionId = Context.ConnectionId;
var user = Users.GetOrAdd(profileId, _ => new User
{
ProfileId = profileId,
ConnectionIds = connectionId
});
lock (user.ConnectionIds)
{
Groups.Add(connectionId, user.ProfileId);
}
return base.OnConnected();
}
return null;
}
[HubMethodName("sendNotifications")]
public Task SendNotifications(string id)
{
UserID = id;
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
string query = "SELECT NotificationNumber FROM [dbo].[NotificationStatus] WHERE UserID=" + UserID;
connection.Open();
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Notification = null;
DataTable dt = new DataTable();
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
dt.Load(reader);
if (dt.Rows.Count > 0)
{
totalNewMessages = Int16.Parse(dt.Rows[0]["NotificationNumber"].ToString());
}
}
}
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
//return context.Clients.All.RecieveNotification(totalNewMessages);
return context.Clients.Client(Users.Values.FirstOrDefault(i => i.ProfileId == UserID).ConnectionIds).RecieveNotification(totalNewMessages);
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
NotificationHub nHub = new NotificationHub();
nHub.SendNotifications(UserID);
}
}
}
}
这里有很多错误,您应该先阅读一些关于 SignalR 概念的优秀基础文档。你提到的指南很差。您应该检查的主要内容:
- 每次从客户端调用集线器方法时,SignalR 都会从头开始创建集线器,然后将其销毁,因此对于像这样基本的东西,你不应该干涉它,而是用你的事件处理程序
- 由于前一点,您的
UserID
成员根本不在正确的位置,它 有点 对您有用只是因为错误的副作用正在生成更多错误(如下所述):不要存储任何应该在集线器实例成员内部的调用中存在的状态,它并不意味着可以生存
- 你明确地为与 SignalR 广播无关的事情做了
new NotificationHub()
,你应该将 sql 依赖项移到中心之外并在那里做,而让中心做他们的只拥有自己的东西
- 当您更改页面时您的连接丢失,购买您的事件处理程序(可能)人为地使 "dead" 集线器实例保持活动状态,并将其用于通知,但这是完全错误的
您应该检查您的设计,从管理集线器外部的 sql 依赖项开始。您已经了解 IHubContext
,因此从外部集线器使用它,并且您应该仅将集线器用于它们的用途,而不是在将它们附加到依赖事件时人为地保持它们的活动状态,或者更糟糕的是,明确地创建它们。你正在走向纠缠不清的意大利面条代码,这很难推理和理解,正如你正在经历的那样。
您好,感谢您阅读本文。
我用这个guide作为我的基础,我只添加了Owin Login/Registration(cookie)
当我登录时,它显示来自我的 NotificationHub 的通知,我能够更新数据库并立即运行更新。所以一切正常,直到您尝试切换页面,然后通知停止。即使我只是更新当前页面。
可能是什么问题?
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System.Security.Claims;
using System.Collections.Concurrent;
namespace LifeChange
{
[HubName("notificationHub")]
public class NotificationHub : Hub
{
private static readonly ConcurrentDictionary<string, User> Users = new ConcurrentDictionary<string, User>(StringComparer.InvariantCultureIgnoreCase);
private static List<User> UserList = new List<User>();
Int16 totalNewMessages = 0;
string UserID;
[HubMethodName("check")]
public Task Check(string id)
{
if (!Users.ToList().Exists(i => i.Value.ProfileId == id))
{
string profileId = id; //Context.QueryString["id"];
string connectionId = Context.ConnectionId;
var user = Users.GetOrAdd(profileId, _ => new User
{
ProfileId = profileId,
ConnectionIds = connectionId
});
lock (user.ConnectionIds)
{
Groups.Add(connectionId, user.ProfileId);
}
return base.OnConnected();
}
return null;
}
[HubMethodName("sendNotifications")]
public Task SendNotifications(string id)
{
UserID = id;
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
string query = "SELECT NotificationNumber FROM [dbo].[NotificationStatus] WHERE UserID=" + UserID;
connection.Open();
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Notification = null;
DataTable dt = new DataTable();
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
dt.Load(reader);
if (dt.Rows.Count > 0)
{
totalNewMessages = Int16.Parse(dt.Rows[0]["NotificationNumber"].ToString());
}
}
}
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
//return context.Clients.All.RecieveNotification(totalNewMessages);
return context.Clients.Client(Users.Values.FirstOrDefault(i => i.ProfileId == UserID).ConnectionIds).RecieveNotification(totalNewMessages);
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
NotificationHub nHub = new NotificationHub();
nHub.SendNotifications(UserID);
}
}
}
}
这里有很多错误,您应该先阅读一些关于 SignalR 概念的优秀基础文档。你提到的指南很差。您应该检查的主要内容:
- 每次从客户端调用集线器方法时,SignalR 都会从头开始创建集线器,然后将其销毁,因此对于像这样基本的东西,你不应该干涉它,而是用你的事件处理程序
- 由于前一点,您的
UserID
成员根本不在正确的位置,它 有点 对您有用只是因为错误的副作用正在生成更多错误(如下所述):不要存储任何应该在集线器实例成员内部的调用中存在的状态,它并不意味着可以生存 - 你明确地为与 SignalR 广播无关的事情做了
new NotificationHub()
,你应该将 sql 依赖项移到中心之外并在那里做,而让中心做他们的只拥有自己的东西 - 当您更改页面时您的连接丢失,购买您的事件处理程序(可能)人为地使 "dead" 集线器实例保持活动状态,并将其用于通知,但这是完全错误的
您应该检查您的设计,从管理集线器外部的 sql 依赖项开始。您已经了解 IHubContext
,因此从外部集线器使用它,并且您应该仅将集线器用于它们的用途,而不是在将它们附加到依赖事件时人为地保持它们的活动状态,或者更糟糕的是,明确地创建它们。你正在走向纠缠不清的意大利面条代码,这很难推理和理解,正如你正在经历的那样。