Taylor Mitchell
Taylor Mitchell

Reputation: 613

Signalr not working from controller, I assume it's not finding clients

I'm trying to broadcast a message from a controller. Basically what I'm trying to do is send a notification to everyone's dashboard whenever a specific object is saved. In my JS I have the connect method and I can send messages to the server and get messages back from it, so I know I'm connected to the hub, however in my controller using the GlobalHost.ConnectionManager.GetHubContext<MyHub>() method to get the context it doesn't seem to send to any of the clients.

Hub

public class UpdateHub : Hub
{
    public void Update()
    { 
        Clients.All.update("You've reached the hub");
    }
}

Controller(after my model is saved, but before returning the view, the model saves, and it runs)

var updateHubContext = GlobalHost.ConnectionManager.GetHubContext<UpdateHub>();
updateHubContext.Clients.All.update("A new model has been saved");

Debugging on the update method revealed...

updateHubContext.Clients.All.update("A new model has been saved");
Id = 1714, Status = RanToCompletion, Method = "{null}", Result = ""
AsyncState: null
CancellationPending: false
CreationOptions: None
Exception: null
Id: 1714
Result: null
Status: RanToCompletion

But if it ran to completion why didn't the client see it? If I send the update method to the server the client then sees it.

var myhub = $.connection.notificationHub;
myhub.server.Update();
myhub.client.update = function(message) {
    alert(message);
}
$.connection.hub.start();

any ideas where I'm going wrong here?

Also I'm using Autofac, I don't think the issue is there, but here's the code for it.

var config = new HubConfiguration();
var builder = new ContainerBuilder();

builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterHubs(Assembly.GetExecutingAssembly()).SingleInstance();
var container = builder.Build();
config.Resolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(container);
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver((IContainer)container);

app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
app.MapSignalR("/signalr", config);

ConfigureAuth(app);

Upvotes: 1

Views: 855

Answers (2)

Taylor Mitchell
Taylor Mitchell

Reputation: 613

I needed to inject a lifetime scope into it for Autofac.

private readonly ILifetimeScope _hubLifetimeScope;
public UpdateHub(ILifetimeScope lifetimeScope)
{
    _hubLifetimeScope = lifetimeScope.BeginLifetimeScope("AutofacWebRequest");
}

It's in the docs. Also I needed to Register the Hubs with Autofac individually and as ExternallyOwned.

Upvotes: 1

Sayan Pal
Sayan Pal

Reputation: 4956

You may try something like this:

var myhub = $.connection.notificationHub;

myhub.client.update = function(message) {
    alert(message);
}

$.connection.hub.start().done(function(){
    myhub.server.update();    
});

You need to register one client callback method before starting the connection. The below is from ASP.NET SignalR Hubs API Guide - JavaScript Client - How to establish a connection

Note: Normally you register event handlers before calling the start method to establish the connection. If you want to register some event handlers after establishing the connection, you can do that, but you must register at least one of your event handler(s) before calling the start method. ...

Also I think you were trying to call a method on server prior to starting the connection.

Hope this helps.

Upvotes: 1

Related Questions