Page 47 - MSDN Magazine, July 2018
P. 47
Figure 1 Counting Connections
functional hub with the connection set up through it. When the user leaves the browser, or just the application, the connection is released and listening clients notified. As in ASP.NET Core SignalR, there’s no support for automatic reconnections, so things are even easier. All you do is define a global static variable in the hub and increment its value up or down when a user connects or discon- nects, as shown in Figure 1. The SignalR runtime in ASP.NET Core ensures that every connection is closed at some point, and any new connection effectively refers to a new connection. In short, the number you get is highly reliable.
There’s one drawback to counting users with SignalR: It only works if users visit the page that establishes a connection to the hub where counting takes place. To be on the safe side, you need to have a SignalR client in nearly any page the user can visit. This is especially true if you consider that normally the number of online users is a globally visible value you probably have in all layouts on which your views are based.
Note that in the sample hub code, the class calls back the con- nected clients every time a connection is created or closed. Note also that in this way you only have the total number of users, but not the list of connection IDs or, in case of authenticated users, the list of user names. To achieve this, you better use a dictionary instead of a global counter and add to it entries with connection IDs or claims, such as the user name.
There’s one drawback
to counting users with SignalR: It only works if users visit the page that establishes a connection to the hub where counting takes place.
Another point to consider with reference to the code in Figure 1 is the use of a static variable to count users. A static variable is per-server, which means that when you scale out you’ll need to consider how to store shared state in a globally accessible location, such as a database or a distributed cache.
Pushing Information Back
From within the hub, or the hub context if you connect to the back end via a controller method, you have many different ways to call back connected clients. All methods are members exposed by the Clients object that, in spite of the name, is not a collection, but an instance of the IClientProxy class. The expressions in Figure 2 indicate the object from which the SendAsync method is invoked. The SendAsync method takes the name of the client method to call back and the parameters to pass.
A group is a collection of related clients collectively gathered under a name. The more natural way of thinking of groups in
public class SampleHub : Hub {
private static int Count = 0;
public override Task OnConnectedAsync() {
Count++;
base.OnConnectedAsync(); Clients.All.SendAsync("updateCount", Count); return Task.CompletedTask;
}
public override Task OnDisconnectedAsync(Exception exception) {
Count--; base.OnDisconnectedAsync(exception); Clients.All.SendAsync("updateCount", Count); return Task.CompletedTask;
} }
The only difference between using a hub or a controller is that SignalR can’t track the connection ID when a request goes through the controller. If the connection ID is relevant to the server task, then it has to be passed in some way via the URL. All other infor- mation that forms the SignalR caller context can be retrieved by the controller via the HTTP request context.
Counting Online Users
Some Web applications find it useful, or just engaging for users, to show how many connections are currently active. The problem is not so much tracking when a user connects—there are many end- points through which you can detect that—but rather when a user disconnects from the application.
You can audit a login page or the post-authentication step. You can place a check in some base controller class or in any of the pages that the user can visit. In general, you can always find a way to detect when a user connects to the application. The problem is how the user can leave the application, whether by logging out (easily traceable) or by navigating away from the page or by shutting down the browser window. There’s no reliable way to detect when the user closes the browser window. Yes, browsers usually fire the beforeunload event when the browser shuts down, but this same event is also fired whenever you follow a link—even when that link is within the same application. So it’s not a perfect solution.
A much more reliable way to count users is to keep track of ASP.NET Core SignalR connections. To do this, you need a fully
Figure 2 Methods for the Server to Call Back Connected Clients
Expression
Description
Clients.All
The notification is broadcast to all connected clients, regardless of the technology being used (Web. .NET, .NET Core, Xamarin).
Clients.Client(connectionId)
The notification is sent exclusively to the client listening over the specified connection.
Clients.User(userId)
The notification is sent to all clients whose authenticated user matches the provided user name.
Clients.Groups(group)
The notification is sent to all clients belonging to the specified group.
msdnmagazine.com
June 2018 41