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,因此从外部集线器使用它,并且您应该仅将集线器用于它们的用途,而不是在将它们附加到依赖事件时人为地保持它们的活动状态,或者更糟糕的是,明确地创建它们。你正在走向纠缠不清的意大利面条代码,这很难推理和理解,正如你正在经历的那样。