Home > database >  How do I correctly inject a SignalR hub in an ASP.NET controller?
How do I correctly inject a SignalR hub in an ASP.NET controller?

Time:01-21

I'm trying to use SignalR to send an update through a websocket when a request is made to an endpoint. But, I'm struggling to inject the relevant Controller with a hub dependency. I've got a controller with the following GET function:

[HttpGet]
public IEnumerable<Zaal> GetZaal()
{
    new BoekingUpdateHub().SendData("Test");
    foreach(Stoel s in _context.Stoel)
    {
        Console.WriteLine(s.Id);
    }
    return _context.Zaal;
}

Problem is, when I try to use this endpoint, the hub is not instantiated properly, as

public class BoekingUpdateHub : Hub
{
    public async Task SendData(string data)
    {
        await Clients.All.SendAsync("ReceiveData", data);
    }
}

Gives me a null reference exception on the await Clients.All, as Clients was null

I've tried using dependency injection to resolve this problem, but it gives me:

System.InvalidOperationException: Unable to resolve service for type 'WDPR.Hubs.BoekingUpdateHub' while attempting to activate 'WDPR.Controllers.ZaalController'.

I've looked around and I can't find a solution, I'm completely lost on how to implement this properly.

CodePudding user response:

I figured it out. Rather than putting the Hub as an argument in the constructor, you add IHubContext as an argument, in this case the T is the Hub you want to actually use (in my case the hub is called MyHub)

private readonly DbTheaterLaakContext _context;
private readonly IHubContext<MyHub> _hubContext;

public ZaalController(DbTheaterLaakContext context, IHubContext<BoekingUpdateHub> hubContext)
{
    _context = context;
    _hubContext = hubContext;
}

Then, you can create the Hub inside one of the Endpoint functions:

[HttpGet]
public IEnumerable<Zaal> GetZaal()
{
    new MyHub(_hubContext).SendData("Zaal GET request received");
}

Finally, make sure the IHubContext is an argument in the Hub's constructor:

public class MyHub: Hub
{
    protected IHubContext<MyHub> _context;

    public MyHub(IHubContext<MyHub> context)
    {
        this._context = context;
    }
    public async Task SendData(string data)
    {
        await _context.Clients.All.SendAsync("ReceiveData", data);
    }
}

Now, notice we're using the IHubContext as a source for our Clients, this prevents the Clients from being null. Doing these steps allows you to send information through a SignalR websocket when an endpoint receives a request.

CodePudding user response:

Configure the controller as follows

public class DemoController : ControllerBase
{
  private readonly IHubContext<MyHub> _hubContext;
  public DemoController(
        IHubContext<MyHub> hubContext
        )
    {
        _hubContext = hubContext;
    }

  [HttpGet]
  public IEnumerable<Zaal> GetZaal()
  {
    _hubContext.Clients.All.SendData("Zaal GET request received");
  }
}
  • Related