1
votes

Environment:

  • Visual Studio 2017 Community with latest updates
  • Target Framework: .NET Core 2.1 (latest version)
  • SignalR Core
  • Running on IIS Express on Windows 10 (dev environment)

TL;DR: Injecting IHubContext<> into Controller ctor so Action method can send message to clients doesn't seem to be working.

Long version:

I have a basic ASP.NET Core test application working and .NET clients are able to connect and send/receive messages. So my Hub and Clients appear to be working fine.

I'm now trying to add a controller to the same VS project that the SignalrR Hub is in so that external actors can send messages via a REST API endpoint.

To do this I've tried using DI to inject IHubContext<> into the ctor of my controller as follows:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : Controller
{
    private IHubContext<OrgHub> _hubContext;
    public ValuesController(IHubContext<OrgHub> hubContext)
    {
        _hubContext = hubContext;
    }

    //...

}

This appears to be successfully injecting the right IHubContext because when I debug the private members I see the number of connections = 1 when I have 1 .NET client connected.

Now the trouble: within an action method I try to use the _hubContext to call a hub method... but nothing happens. The debugger passes by the line of code and no breakpoints within my Hub are hit. Nothing happens at all. Note that when .NET clients send messages (via the SignalR .NET client) the breakpoints on my Hub are indeed hit. Its just the _hubContext in my Controller/action method that doesn't seem to be working.

Here is what I'm doing in an action method:

    // GET api/values
    [HttpGet]
    public async Task<ActionResult<IEnumerable<string>>> GetAsync()
    {

        //Try to call "SendMessage" on the hub:
        await _hubContext.Clients.All.SendAsync("SendMessage", "SomeUserName", "SomeMessage");

       //...

        return new string[] { "bla", "bla" };
    }

And here is the corresponding Hub method:

 public class OrgHub : Hub
{

    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }

    //...

}

If it helps, here is the edited version of Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {

        services.AddSignalR();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
    {

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();

        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();


        app.UseSignalR(routes =>
        {
            routes.MapHub<OrgHub>("/rpc");
        });


        app.UseMvc();


    }
}

So, any ideas or suggestions on where to go from here? Clearly there must be something I'm overlooking...

thanks!

1

1 Answers

2
votes

That's not how this works. When you call SendAsync that message is going out to the client. You don't call methods on your hub, via SendAsync. Nothing is happening, because the clients are literally getting sent a message that should invoke something listening for "SendMessage" client-side, which presumably is not something you've register your clients to listen for. If the goal is to hit "ReceiveMessage" client-side, then you should be doing SendAsync("ReceiveMessage", ...) in your controller.