问题
I have a simple 1-page web app using the VS2019 Razor Pages template. The hosted service will send data to the page via SignalR. Is it possible to check if the client page (Index page) is loaded because if not then the hosted service will pause sending data? When running from VS2019 the page of course opens automatically but running from "dotnet run" I need to know if the user has loaded the page into the browser e.g. they might shut it down after the service has started.
namespace TestProject
{
public class TestService : IHostedService
{
public TestService(ILogger<TestService> logger)
{
}
public Task StartAsync(CancellationToken cancellationToken)
{
// HERE - check if index page is loaded - how??
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}
回答1:
Implement simple SignalR connection counter
public class SignalRConnectionList
{
private readonly object _sync = new object();
private readonly List<string> _items = new List<string>();
public void Remove(string connectionId)
{
lock (_sync)
{
_items.Remove(connectionId);
}
}
public void Add(string connectionId)
{
lock (_sync)
{
_items.Add(connectionId);
}
}
public int Count
{
get
{
lock (_sync)
{
return _items.Count;
}
}
}
}
In ConfigureServices of Startup class add SignalRConnectionList as singleton
services.AddSingleton<SignalRConnectionList>();
Override OnConnectedAsync and OnDisconnectedAsync methods in Hub class
public class ChatHub: Hub
{
public ChatHub(SignalRConnectionList connectionList)
{
ConnectionList = connectionList;
}
private SignalRConnectionList ConnectionList { get; }
public override Task OnConnectedAsync()
{
ConnectionList.Add(Context.ConnectionId);
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
ConnectionList.Remove(Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
Now in IHostedService you can use connection counter implemented above
public class SimpleService : BackgroundService
{
public SimpleService(
ILogger<SimpleService> logger,
IHubContext<ChatHub> hubContext,
SignalRConnectionList connectionList)
{
Logger = logger;
HubContext = hubContext;
ConnectionList = connectionList;
}
private SignalRConnectionList ConnectionList { get; }
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(1000, cancellationToken);
if (ConnectionList.Count > 0)
{
await HubContext.Clients.All.SendAsync("ReceiveMessage", "system", "ping " + DateTime.Now, cancellationToken);
}
}
}
回答2:
In general you cannot answer the question check if index page is loaded in a web server. The server just serves content to clients that can do whatever they like with that content without the server being informed about the details.
However, if you have a SignalR connection from the client to the server you have state on the server for each connection. I think that is what you need to use to solve your problem.
You can override the OnConnectedAsync
and OnDisconnectedAsync
methods of your SignalR Hub
to keep track of connections. This information can then be shared with your background service that uses IHubContext
to send data to all clients (but only if there are any clients).
来源:https://stackoverflow.com/questions/63717414/asp-net-core-3-1-from-a-hosted-service-check-if-client-index-page-is-loaded