1

I have created a hub in my Web API. It is very simple:

public class DashboardHub : Hub
{
    public async Task SendMessage(InfoSummary infoSummary)
    {
        await Clients.All.SendAsync("ReceiveMessage", infoSummary);
    }
}

I am trying to send a message to the Hub from a controller in the same Web API when data is updated.

I have seen 100 different answers, and nothing works. Basically my hub object in my controller is null, and I can't seem to get it instantiated.

    private readonly IRepository _repo;
    private readonly Helpers.Convert _convert;
    private readonly CoreContext _context;
    private readonly IMapper _mapper;
    private readonly NotifyService _service;
    private readonly DashboardHub _hub;

    public MyController(IRepository repo, 
                                CoreContext context, 
                                IMapper mapper)
        {
            _convert = new Helpers.Convert(repo, mapper);
            _repo = repo;
            _context = context;
            _mapper = mapper;
            _hub = new DashboardHub();
            _service = new NotifyService(_hub);
        }

    [HttpPost("updatestatus")]
    public async Task<IActionResult> UpdateStatus(Header header) {

        var returnVal = await _repo.ChangeStatus(header.HeaderId, header.Status);

        headerSummary = _convert.ToReturnStatusHeader( await _repo.GetHeader(header.HeaderId));
        // await _service.SendNotificationAsync(headerSummary);
        await _hub.SendMessage(headerSummary);        

        return Ok(returnVal);
    }

I have the

services.AddSignalR();
services.AddScoped(typeof(DashboardHub));

and

endpoints.MapHub<DashboardHub>("/Hubs/DashboardHub");

in the proper sections in the startup.cs file

I know I am missing something very small, but I would love to know what it is.

I have also tried creating a strongly typed hub, but that introduced even more problems.

Thanks in advance.

Coder B
  • 81
  • 1
  • 8

3 Answers3

0

Well, I feel like a complete and utter newb. The fix is very simple. You must add the using statement telling the controller you want to use SignalR. OMG.. I am almost too embarrassed to put this up, but hope it will help someone else.

FIX:

using Microsoft.AspNetCore.SignalR;

:facepalm

Coder B
  • 81
  • 1
  • 8
0

You have done there or four mistakes.

  1. You don't need this line to be in your ConfigureServices method of Startup.cs. services.AddScoped(typeof(DashboardHub));

    Remove it. Just keep services.AddSignalR();

  2. Why are you using new key word, since .net core provide in-built dependency injection service. Remove below lines.

    _hub = new DashboardHub();
    _service = new NotifyService(_hub); 
    

    Instead create a new interface INotifyService.cs for NotifyService.cs. Register this service in ConfigureServices method of Startup.cs.

    services.AddScoped<INotifyService, NotifyService>();

  3. Your MyController.cs should be like below

    Add this line. using Microsoft.AspNetCore.SignalR;

    private readonly IRepository _repo;
    private readonly Helpers.Convert _convert;
    private readonly CoreContext _context;
    private readonly IMapper _mapper;
    private readonly INotifyService _service;
    private readonly IHubContext<DashboardHub> _hubContext

    public MyController(IRepository repo, CoreContext context, IMapper mapper,INotifyService service,IHubContext<DashboardHub> hubContext)
        {
            _convert = new Helpers.Convert(repo, mapper);
            _repo = repo;
            _context = context;
            _mapper = mapper;
            _service = service;
            _hubContext = hubContext;
        }

    [HttpPost("updatestatus")]
    public async Task<IActionResult> UpdateStatus(Header header) {

        var returnVal = await _repo.ChangeStatus(header.HeaderId, header.Status);

        headerSummary = _convert.ToReturnStatusHeader( await _repo.GetHeader(header.HeaderId));
        // await _service.SendNotificationAsync(headerSummary);

        await hubContext.Clients.All.SendAsync("ReceiveMessage", headerSummary);

        return Ok(returnVal);
    }
  1. Use same concept if you are sending messages inside your NotifyService.cs.
  • Thanks! I will make those additional changes. I think those were from code I had found. As I said, I had tried many things. I prefer injection, and not sure why I didn't do it that way in the first place. The big thing I was missing was the using statement (facepalm) – Coder B Jan 11 '20 at 14:11
-1

What you could do is inject your hub using dependency injection in your controller. You can't just instanciate the hub in the controller like you are doing, and I would change it to a Singleton also.

services.AddSingleton(typeof(DashboardHub));
internal DashboardHub DashboardHub
{
    get
    {
        return this.HttpContext.RequestServices.GetRequiredService<DashboardHub>();
    }
}
Kiril1512
  • 3,231
  • 3
  • 16
  • 41