如何使用 ASP.NET MVC + SignalR 强制服务器不断发送事件数据?
How to force a server to send an event-data constantly, using ASP.NET MVC + SignalR?
ExportClient
class 有 OnTickRecieved
事件,这有助于我接收一些数据(来自市场的出价)。我只想在浏览器的图表上实时接收这些数据。当我按下 UI 端的 Go
按钮时,它会调用控制器中的 Go()
方法,然后什么也没有发生。这是合乎逻辑的 - 因为在服务器请求之后,控制器被销毁。
我的问题是:如何强制服务器不断向我发送事件数据?
控制器代码:
public class ChartsController : Controller
{
[HttpGet]
public void Go()
{
var exportClient = new ExportClient();
exportClient.TickRecieved += exportClient_TickRecieved;
}
private void exportClient_TickRecieved(object sender, TickRecievedEventArgs args)
{
ImpulserHub.SendBidPrice(args.Bid);
}
}
集线器代码:
[HubName("impulserHub")]
public class ImpulserHub : Hub
{
public static void SendBidPrice(double bid)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ImpulserHub>();
hubContext.Clients.All.sendBidPrice(bid);
}
}
而且我已经测试了 SignalR,这段代码工作正常:
[HttpGet]
public void Go()
{
ImpulserHub.SendBidPrice(3.3333333); // I have received this number on UI
}
最简单的方法是将您的导出客户端作为单例或静态变量,并在全局范围内向您注册事件(可能在 Global.asax.cs 中的 Application_Start()
方法中)。您的集线器代码也应该移出,因为集线器像控制器一样是瞬态的。
这是它的样子:
private ExportClient _exportClient;
private IHubContext _impulserHub;
protected void Application_Start()
{
_exportClient = new ExportClient();
exportClient.TickRecieved += exportClient_TickRecieved;
_impulserHub = GlobalHost.ConnectionManager.GetHubContext<ImpulserHub>();
}
private void exportClient_TickRecieved(object sender, TickRecievedEventArgs args)
{
_impulserHub.Clients.All.sendBidPrice(args.Bid);
}
此代码仍然存在问题。 IIS 将拆除未主动接收请求的网站。这意味着即使触发了事件,代码也可能随时停止工作。管理应用程序拆卸很困难,因为应用程序启动和停止之间的状态必须为 saved/transferred。除非您可以将 IIS 设置为永不拆除您的应用程序(大多数情况下在共享或云托管上是不可能的),否则您应该尝试使用 HangFire library which is available as a nuget package。它是专门为该用例设计的,并进行了一些重构,您的代码可能如下所示:
private ExportClient _exportClient;
private IHubContext _impulserHub;
protected void Application_Start()
{
_exportClient = new ExportClient();
exportClient.TickRecieved += exportClient_TickRecieved;
_impulserHub = GlobalHost.ConnectionManager.GetHubContext<ImpulserHub>();
BackgroundJob.Schedule(() => _impulserHub.Clients.All.sendBidPrice(_exportClient.GetBid()), TimeSpan.FromSeconds(5));
}
ExportClient
class 有 OnTickRecieved
事件,这有助于我接收一些数据(来自市场的出价)。我只想在浏览器的图表上实时接收这些数据。当我按下 UI 端的 Go
按钮时,它会调用控制器中的 Go()
方法,然后什么也没有发生。这是合乎逻辑的 - 因为在服务器请求之后,控制器被销毁。
我的问题是:如何强制服务器不断向我发送事件数据?
控制器代码:
public class ChartsController : Controller
{
[HttpGet]
public void Go()
{
var exportClient = new ExportClient();
exportClient.TickRecieved += exportClient_TickRecieved;
}
private void exportClient_TickRecieved(object sender, TickRecievedEventArgs args)
{
ImpulserHub.SendBidPrice(args.Bid);
}
}
集线器代码:
[HubName("impulserHub")]
public class ImpulserHub : Hub
{
public static void SendBidPrice(double bid)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ImpulserHub>();
hubContext.Clients.All.sendBidPrice(bid);
}
}
而且我已经测试了 SignalR,这段代码工作正常:
[HttpGet]
public void Go()
{
ImpulserHub.SendBidPrice(3.3333333); // I have received this number on UI
}
最简单的方法是将您的导出客户端作为单例或静态变量,并在全局范围内向您注册事件(可能在 Global.asax.cs 中的 Application_Start()
方法中)。您的集线器代码也应该移出,因为集线器像控制器一样是瞬态的。
这是它的样子:
private ExportClient _exportClient;
private IHubContext _impulserHub;
protected void Application_Start()
{
_exportClient = new ExportClient();
exportClient.TickRecieved += exportClient_TickRecieved;
_impulserHub = GlobalHost.ConnectionManager.GetHubContext<ImpulserHub>();
}
private void exportClient_TickRecieved(object sender, TickRecievedEventArgs args)
{
_impulserHub.Clients.All.sendBidPrice(args.Bid);
}
此代码仍然存在问题。 IIS 将拆除未主动接收请求的网站。这意味着即使触发了事件,代码也可能随时停止工作。管理应用程序拆卸很困难,因为应用程序启动和停止之间的状态必须为 saved/transferred。除非您可以将 IIS 设置为永不拆除您的应用程序(大多数情况下在共享或云托管上是不可能的),否则您应该尝试使用 HangFire library which is available as a nuget package。它是专门为该用例设计的,并进行了一些重构,您的代码可能如下所示:
private ExportClient _exportClient;
private IHubContext _impulserHub;
protected void Application_Start()
{
_exportClient = new ExportClient();
exportClient.TickRecieved += exportClient_TickRecieved;
_impulserHub = GlobalHost.ConnectionManager.GetHubContext<ImpulserHub>();
BackgroundJob.Schedule(() => _impulserHub.Clients.All.sendBidPrice(_exportClient.GetBid()), TimeSpan.FromSeconds(5));
}