-
Notifications
You must be signed in to change notification settings - Fork 0
Hubs
Hubs provide a higher level RPC framework over a PersistentConnection. If you have different types of messages that you want to send between server and client then hubs is recommended so you don't have to do your own dispatching.
To get started using Hubs, create a class that derives from Hub.
public class MyHub : Hub
{
}Unlike low level PersistentConnections, there's no need to specify a route for the hub as they are automatically accessible over a special url (/signalr). This url is configurable:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHubs("~/signalr2");
}
}The above changes the default hubs url to signalr2
Note: You can also specify a name other than the type name for the Hub using the [HubName("...")] attribute.
To expose methods on the hub that you want to be callable from the client. Simply declare a public method:
public class MyHub : Hub
{
public string Send(string data)
{
return data;
}
}This makes the Send method callable from any SignalR client.
SignalR will handle the binding of complex objects and arrays of objects automatically.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class MyHub : Hub
{
public string ExtractName(Person person)
{
return person.Name;
}
}To call client event/methods from the server use the Clients property.
public class MyHub : Hub
{
public void Send(string data)
{
Clients.addMessage(data);
}
}The above code will invoke the addMessage method on the client with specified data.
NOTE: Parameters passed to the method will be JSON serialized before being sent to the client
Invoking methods on the the Clients property will broadcast that message to all connected clients. But there are some cases where we want to send a message to specific clients or groups. We can use the indexer on the Clients object to specify a connection id. You can also use the Caller property on the Hub to invoke methods on the calling client.
public class MyHub : Hub
{
public void Send(string data)
{
// Invoke a method on the calling client
Caller.addMessage(data);
// Similar to above, the more verbose way
Clients[Context.ConnectionId].addMessage(data);
}
}NOTE: Even if the group/client does not exist, the indexer will never be null.
You can add connections to groups and send messages to particular groups. Groups are not persisted on the server so applications are responsible for keeping track of what connections are in what groups so things like group count can be achieved.
public class MyHub : Hub, IDisconnect
{
public Task Join()
{
return Groups.Add(Context.ConnectionId, "foo");
}
public Task Send(string message)
{
return Clients["foo"].addMessage(message);
}
public Task Disconnect()
{
return Clients["foo"].leave(Context.ConnectionId);
}
}Under the covers the Clients/Caller property is a dynamic object that wraps an IConnection. Method calls on that object call Broadcast with method invocation data that the clients interprets.
- Anything you return from the hub will be serialized into JSON and sent to the client.
- You may also return Task/Task<T> from a hub if you need to do async work.
Example
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class MyHub : Hub
{
public Person Send(string data)
{
// This will be serialized into JSON
return new Person { Name = "John Doe", Age = 40 };
}
public Task<int> AsyncWork()
{
return Task.Factory.StartNew(() =>
{
// Don't do this in the real world
Thread.Sleep(500);
return 10;
});
}
}- Any state sent from the client can be accessed via the Caller property.
- You can also set client side state just by setting any property on Caller.
Example
public class MyHub : Hub
{
public void Send(string data)
{
// Access the id property set from the client.
string id = Caller.id;
// Set a property on the client state
Caller.name = "SignalR";
}
}Unlike PersistentConnections, Hubs don't have a Connect, Reconnect or Disconnect event. To detect disconnects when using hubs, implement the IDisconnect interface. To detect connects and reconnects, implement IConnected:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SignalR.Hosting;
using SignalR.Hubs;
namespace ConnectDisconnectDemo
{
public class Status : Hub, IDisconnect, IConnected
{
public Task Disconnect()
{
return Clients.leave(Context.ConnectionId, DateTime.Now.ToString());
}
public Task Connect()
{
return Clients.joined(Context.ConnectionId, DateTime.Now.ToString());
}
public Task Reconnect(IEnumerable<string> groups)
{
return Clients.rejoined(Context.ConnectionId, DateTime.Now.ToString());
}
}
}Whenever a client disconnects, the Disconnect method will be invoked on all hubs that implement IDisconnect. When this method is called you can use Context.ConnectionId to access the client that disconnected.
NOTE: This method is called from the server, that means state on the Caller object, any state that was with the connection, as well as the HubContext's User and Cookies will not be populated.
NOTE: Hubs are per call, that is, each call from the client to the hub will create a new hub instance. So don't setup static event handlers in hub methods.
- Gets the HubContext for this hub request.
- Gets the dynamic object that represents the calling client (i.e the client that invoked the hub method).
- Gets the dynamic object that represents all connected clients.
- Gets the group manager for this Hub.
Encapsulates all Connection-specific information about an individual Hub request.
- Gets client id of the client that invoked the hub.
- Gets the cookies that were part of the http request.
- Gets the querystring values that were part of the http request.
- Gets the headers that were part of the http request.
- Gets the user that was part of the initial http request.
Sometimes you have some arbitrary code in an application that you want to be able to notify all clients connected when some event occurs. An example of this might be a background task that sends data at a certain interval.
You can use the dependency resolver for the current host to resolve the IConnectionManager interface which allows you to get ahold of the context object for a hub.
using System;
using System.Web.Routing;
using SignalR;
using SignalR.Hubs;
namespace WebApplication1
{
public class Notifier
{
public static void Say(string message)
{
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.say(message);
}
}
}Once you have the context, you can call methods on all connections, or groups of connections:
using System;
using System.Web.Routing;
using SignalR;
using SignalR.Hubs;
namespace WebApplication1
{
public class Notifier
{
public static void Say(string group, string message)
{
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients[group].say(message);
}
}
}You can also add/remove connections to groups:
using System;
using System.Web.Routing;
using SignalR;
using SignalR.Hubs;
namespace WebApplication1
{
public class MemberManager
{
public static void AddConnection(string connectionId, string groupName)
{
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Groups.Add(connectionId, groupName);
}
public static void RemoveConnection(string connectionId, string groupName)
{
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Groups.Remove(connectionId, groupName);
}
}
}