javascript - 刷新页面后SignalR收到越来越多的消息

标签 javascript c# asp.net signalr signalr-hub

我在 ASP.NET 中编写了一个 Web 应用程序,它通过 SignalRC# 程序交换数据。 这是我的代码的相关部分。当然,如果我忘记了解决我的问题的重要内容,请在评论中询问。

ASP.NET

HubClientManager.cs

using Microsoft.AspNet.SignalR.Client;
using System;
using System.Threading.Tasks;
using System.Diagnostics;

namespace MyProject
{
    public class HubClientManager
    {
        public String GetServerURI()
        {
            return String.Concat("http://192.168.1.103", ":8080", "/signalr");
        }

        public IHubProxy GetHub()
        {
            var hubConnection = new HubConnection(GetServerURI());
            var hub = hubConnection.CreateHubProxy("liveHub");

            try
            {
                var task = hubConnection.Start();
                Task.WhenAll(task).Wait();
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
            return hub;
        }
    }
}

Index.cshtml

<script src="@ViewBag.serverURI/hubs"></script>
<script>
    $(function () {   
        $.connection.hub.url = "@ViewBag.serverURI";
        var hub = $.connection.liveHub;

        hub.client.orderStatus = function (opened, suspended, running, closed, cancelled) {
            $("#cntOpened").text(opened);
            $("#cntSuspended").text(suspended);
            $("#cntRunning").text(running);
            $("#cntClosed").text(closed);
            $("#cntCancelled").text(cancelled);
        };

        $.connection.hub.logging = true;

        $.connection.hub.start().done(function () { });

        $.connection.hub.error(function (error) {
            console.log('SignalR error: ' + error)
        });
    });
</script>

MachinesController.cs

public class MachinesController : Controller
{
    private HubClientManager _manager = new HubClientManager();
    private IHubProxy _hub;

    public MachinesController()
    {
        _hub = _manager.GetHub();
    }

    // GET: Machines
    public ActionResult Index()
    {
        ViewBag.serverURI = _manager.GetServerURI();
        return View(...);
    }

    ...
}

C#

Hub.cs

namespace MyProject.Hubs
{
    public class LiveHub : Hub
    {
        private readonly Erp _erp;

        public LiveHub(Erp erp)
        {
            _erp = erp;
            _erp.HubSendOrderStatus += Erp_HubSendOrderStatus;
        }

        private void Erp_HubSendOrderStatus(int arg1, int arg2, int arg3, int arg4, int arg5)
        {
            Clients.All.orderStatus(arg1, arg2, arg3, arg4, arg5);
        }

        ...    

        public override Task OnConnected()
        {
            _erp.SendOrderStatus();       
            return base.OnConnected();
        }
    }
}

一切正常:我可以在网页中显示来自 C# 应用程序(来自 Erp 类)的数据,并将命令从网页发送回引擎应用程序。这里我只报告了一小部分函数,​​但它们应该足以理解发生的情况。

也许我是盲目的,看这些例子我看不到我的错误。 无论如何,每次我在浏览器中刷新页面,甚至加载同一应用程序的另一个页面(当然共享上面相同的 JavaScript 代码)时,我都会收到越来越多的 SignalR消息!我的意思是,如果我第一次每 10 秒收到 orderStatus 消息,那么在重新加载(或页面更改)后,我每 10 秒收到 2 条消息。再次刷新,它们变成 3,依此类推...一段时间后,整个系统变得无法使用,因为它一次收到数千条消息。

我知道有 OnDisconnected() 回调,但框架似乎调用它来通知客户端已断开连接(我没兴趣知道它)。

更新

我无法发布整个 Erp 类,因为它有 3k+ 行长...无论如何,大多数代码都执行所有其他类型的操作(数据库、现场通信等...)。这里是与集线器相关的唯一功能:

public event Action<int, int, int, int, int> HubSendOrderStatus;

public void SendOrderStatus()
{
    using (MyDBContext context = new MyDBContext())
    {
        var openedOrders = context.Orders.AsNoTracking().Count(x => x.State == OrderStates.Opened);
        var suspendedOrders = context.Orders.AsNoTracking().Count(x => x.State == OrderStates.Suspended);
        var runningOrders = context.Orders.AsNoTracking().Count(x => x.State == OrderStates.Running || x.State == OrderStates.Queued);
        var closedOrders = context.Orders.AsNoTracking().Count(x => x.State == OrderStates.Completed);
        var cancelledOrders = context.Orders.AsNoTracking().Count(x => x.State == OrderStates.Cancelled);

        HubSendOrderStatus?.Invoke(openedOrders, suspendedOrders, runningOrders, closedOrders, cancelledOrders);
    }
}

public async Task ImportOrdersAsync()
{
    // doing something with I/O file
    SendOrderStatus();
}

public void JobImportOrders()
{
    Timer t = null;
    t = new Timer(
    async delegate (object state)
    {
        t.Dispose();
        await ImportOrdersAsync();
        JobImportOrders();
    }, null, 10 * 1000, -1);
}

public Erp()
{
    // initialize other stuff
    JobImportOrders();
}

编辑

AutofacContainer.cs

public class AutofacContainer
{
    public IContainer Container { get; set; }
    public AutofacContainer()
    {
        var builder = new ContainerBuilder();
        var config = new HubConfiguration();
        builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
        builder.RegisterType<Erp>().PropertiesAutowired().InstancePerLifetimeScope();
        Container = builder.Build();
        config.Resolver = new AutofacDependencyResolver(Container);
    }
}

最佳答案

根据“Alex - Tin Le”的建议,我发现处理程序并未被删除:

_erp.HubSendOrderStatus -= Erp_HubSendOrderStatus;

我修复了这个奇怪的行为,检查处理程序是否已经注册:

if (!_erp.HubSendOrderStatus_isRegistered())  _erp.HubSendOrderStatus += Erp_HubSendOrderStatus;

HubSendOrderStatus_isRegistered 函数是这样的:

public bool HubSendOrderStatus_isRegistered()
{
    return HubSendOrderStatus != null;
}

我解决了最初的问题:建立新连接时不再出现大量消息。

最后一点我不明白的是为什么它每次发送 2 条消息而不管事件连接的数量。调试 Javascript 和服务器代码时,我注意到 $.connection.hub.start().done(function () { }); 按预期建立了新连接。但刷新页面时,甚至在任何可用断点之前,已经创建了另一个。但是删除“显式”会导致接收不到任何消息。

关于javascript - 刷新页面后SignalR收到越来越多的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60551726/

相关文章:

asp.net - VB.Net 路径中的反斜杠

javascript - Bot Framework 版本 4 : changes in botchat. cs、styles.css 和 botchat.js 与版本 3 相比

c# - .NET 3.5 中是否有支持超过 2 ^ 31 个项目的集合类或特殊数据类型?

javascript - php/javascript 中的 SSL websocket

javascript - 从另一个表单中包含的文本字段传递参数

c# - 哪一个是更好的架构/设计方法?

asp.net - Orchard CMS - 刚刚通过 WPI 安装,给出错误 500

asp.net - 在 IIS 7 中使用 session 时出错

javascript - jQuery Mobile 1.4.3 修复了工具栏和页面内容问题

javascript - 'li'悬停显示下一个 'ul'