20

I've written a generic hubs which I'm having some issues with so to debug it I've decided to make a simple connection count like so:

public class CRUDServiceHubBase<TDTO> : Hub, ICRUDServiceHubBase<TDTO>
{
    public const string CreateEventName = "EntityCreated";
    public const string UpdateEventName = "EntityUpdated";
    public const string DeleteEventName = "EntityDeleted";

    protected int _connectionCount = 0;

    public Task Create(TDTO entityDTO)
    {
        return Clients.All.InvokeAsync(CreateEventName, entityDTO);
    }

    public Task Update(TDTO entityDTO)
    {
        return Clients.All.InvokeAsync(UpdateEventName, entityDTO);
    }

    public Task Delete(object[] id)
    {
        return Clients.All.InvokeAsync(DeleteEventName, id);
    }

    public override Task OnConnectedAsync()
    {
        this._connectionCount++;
        return base.OnConnectedAsync();
    }

    public override Task OnDisconnectedAsync(Exception exception)
    {
        this._connectionCount--;
        return base.OnDisconnectedAsync(exception);
    }
}

public class MessagesHub : CRUDServiceHubBase<MessageDTO>
{
    public MessagesHub() : base()
    {
    }
}

I'm registering this class like so:

services.AddTransient<ICRUDServiceHubBase<MessageDTO>, MessagesHub>();

I have a service who is using this, which I'm using it's implementation factory to subscribing to it's events:

services.AddTransient<IMessageDTOService>( (c) => {

    var context = c.GetRequiredService<DbContext>();
    var adapter = c.GetRequiredService<IAdaptable<Message, IMessageDTO, MessageDTO>>();
    var validator = c.GetRequiredService<IValidator<Message>>();
    var entityMetadataService = c.GetRequiredService<IEntityMetadataService<Message>>();

    var service = new MessageDTOService(context, adapter, validator, entityMetadataService);
    var hub = c.GetService<ICRUDServiceHubBase<MessageDTO>>();
    this.RegisterHubsCreate(service, hub);

    return service;
});

When I go to fire the event I get a null reference:

Microsoft.AspNetCore.SignalR.Hub.Clients.get returned null.

My best guess is that because the service is a dependency for the controller, It's created before signalR can initialize It's clients?

Does anyone have a suggestion on how I can register my events, and have a client populated?

johnny 5
  • 19,893
  • 50
  • 121
  • 195

1 Answers1

39

I turns out I needed to Inject the IHubContext into my hubs to have access to the clients when I want to invoke server side.

protected IHubContext<CRUDServiceHubBase<TDTO>> _context;

public CRUDServiceHubBase(IHubContext<CRUDServiceHubBase<TDTO>> context)
{
    this._context = context;
}

public Task Create(TDTO entityDTO)
{
    return this._context.Clients.All.InvokeAsync(CreateEventName, entityDTO);
}
johnny 5
  • 19,893
  • 50
  • 121
  • 195
  • When I'm using `Clients`, inside OnConnected method I have valid count and `Clients` method is initialized and I can invoke FE method inside OnConnected, meaning BE and FE are connected properly. Later when I try to send message to all, `Clients` is null, I even tried with context as u described, then I have `Clients`, but count is 0, so nothing happens – Serlok Dec 30 '20 at 09:59
  • @Serlok are you passing in the IHubContext when trying to push? – johnny 5 Dec 30 '20 at 14:16
  • 2
    When I inject IHubContext in my service, it's working, but when I inject it in my Hub, then it's not working, what I had in mind is to send IHubContext from my service to Hub method as an argument – Serlok Dec 30 '20 at 15:16
  • @Serlok I haven't worked on SignalR in a while, but as a guess I don't think you can Inject the HubContext into the Hub because the HubContext is Dependent on the Hub. (I Could be mistaken but thats my best theory ATM) – johnny 5 Dec 30 '20 at 17:40
  • I've injected - no difference – Dmitry Gusarov Feb 14 '21 at 02:23
  • please open a question and drop the link in here and ill take a look at it – johnny 5 Feb 15 '21 at 02:26