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