问题
I have a BackgroundWorker which is supposed to broadcast something to all online clients in 5 seconds interval:
DeactivationBackgroundWorker:
public class DeactivationBackgroundWorker : PeriodicBackgroundWorkerBase, ISingletonDependency
{
private readonly IRepository<HitchRequest, long> _hitchRequestRepository;
private readonly IHitchHub _hitchHub;
public DeactivationBackgroundWorker(AbpTimer timer,
IRepository<HitchRequest, long> hitchRequestRepository,
IHitchHub hitchHub) : base(timer)
{
_hitchRequestRepository = hitchRequestRepository;
Timer.Period = 5000;
_hitchHub = hitchHub;
}
protected override async void DoWork()
{
await broadcastHitchRequestsAsync();
}
[UnitOfWork]
private async Task broadcastHitchRequestsAsync() {
var activeHitchRequests = _hitchRequestRepository.GetAllList(p => p.IsActive);
foreach (var hitchRequest in activeHitchRequests)
{
await _hitchHub.RequestHitch(hitchRequest.Id);
}
}
}
IHitchHub:
public interface IHitchHub: ITransientDependency
{
Task RequestHitch(long hitchId);
}
HitchHub:
public class HitchHub : AbpCommonHub, IHitchHub
{
private readonly IOnlineClientManager _onlineClientManager;
public HitchHub(IOnlineClientManager onlineClientManager, IClientInfoProvider clientInfoProvider): base(onlineClientManager, clientInfoProvider)
{
_onlineClientManager = onlineClientManager;
}
public async Task RequestHitch(long hitchId)
{
var onlineClients = _onlineClientManager.GetAllClients();
foreach (var onlineClient in onlineClients) {
var signalRClient = Clients.Client(onlineClient.ConnectionId);
await signalRClient.SendAsync("receiveHitch", hitchId);
}
}
}
I do not know why the Clients in the HitchHub class is always null! Where should I initialize it?
回答1:
Inject IHubContext<HitchHub>
instead of IHitchHub
.
For example, see ABP's SignalRRealTimeNotifier.
Related issue: https://github.com/aspnet/SignalR/issues/182
回答2:
If your using Asp.net Core see:
Call SignalR Core Hub method from Controller
Otherwise:
Hub's shouldn't be instantiated by yourself or any injection framework
You have to use the ConnectionManager. For your code you should use:
GlobalHost.ConnectionManager.GetHubContext<HitchHub>().RequestHitch(hitchRequest.Id);
**Background information about Hub object lifetime: **
https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server:
You don't instantiate the Hub class or call its methods from your own code on the server; all that is done for you by the SignalR Hubs pipeline. SignalR creates a new instance of your Hub class each time it needs to handle a Hub operation such as when a client connects, disconnects, or makes a method call to the server.
Because instances of the Hub class are transient, you can't use them to maintain state from one method call to the next. Each time the server receives a method call from a client, a new instance of your Hub class processes the message. To maintain state through multiple connections and method calls, use some other method such as a database, or a static variable on the Hub class, or a different class that does not derive from Hub. If you persist data in memory, using a method such as a static variable on the Hub class, the data will be lost when the app domain recycles.
If you want to send messages to clients from your own code that runs outside the Hub class, you can't do it by instantiating a Hub class instance, but you can do it by getting a reference to the SignalR context object for your Hub class. For more information, see How to call client methods and manage groups from outside the Hub class later in this topic.
See also: https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server#callfromoutsidehub
来源:https://stackoverflow.com/questions/48980615/calling-signalr-service-from-a-backgroundworker-in-abp