Detect active users in a page using SignalR and Angular

Detect active users in a page using SignalR and Angular

Sunny Sun Lv4

Bi-directional communication between Angular App and .NET Server

Recently, I implemented an interesting feature using SignalR and Angular. The new feature in the Angular App allows admins to see all active clients on “waiting room” page. The admin can then pick one and start the appointment immediately.

I will share the gist of the solution, which uses SignalR’s bi-directional communication ability and integrates with Angular. Let’s dive in.

Architecture

The technologies used include .Net core, SignalR, and Angular.

SignalR

Although it’s a framework published seven years ago, SignalR still has a unique position in web development. It offers bidirectional communications so that the Server can notify the client instead of the client polling the server.

Under the hood, SignalR uses several transports, including WebSocket, as default. It falls back to other transport methods when WebSocket isn’t available. Compared with HTTP web requests, WebSocket has lower overhead as it doesn’t have the request header and cookies in HTTP Request, which typically takes a few kilobytes per request. Does the few KB data make a difference? In an app handling hundreds of concurrent users, it is a significant overhead.

.Net Core Server

For the sake of simplicity, I will skip all the basic SingnalR setup and boilerplate code for the .Net core application. You can find the source code of the sample solution on GitHub.

The .net core server application exposes a UserHub which allows communication with angular clients. It only contains one public method, as below.

1
2
3
public async Task UserRegister(string userId){  
_sessionCache.UpdateCache(userId);
}

The core functionality resides in the UserSessionCache class, the UserSessoinCache Class is injected into UserHub as Singleton, so there’s only one instance of the class. It manages the incoming user Ids in a UserSession Dictionary object. The in-memory object isn’t persisted in any storage.

1
this.AddOrUpdateUserSession(userId);

It also starts a timer the first time the updateCache method is called. The timer keeps calling the notifyAdmin on the SignalR client.

1
_hub.Clients.All.SendAsync("notifyAdmin", allIds);

Angular

To integrate SignalR in Angular, we need the following package

1
"@aspnet/signalr": "^1.1.4"

Then, we create a service file to handle SignalR-related communication.

First, we created a users observable using RxJs, which holds the data stream down from the SignalR server. In the startConnection function, we build and start the SignalR connection and log the message after the connection is established. Please note that the hard-coded server URL is for demo purposes only; you need to retrieve the URL from the configuration in a real App.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { Injectable } from '@angular/core';
import * as signalR from '@aspnet/signalr';
import { BehaviorSubject } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class SignalrService {
private hubConnection: signalR.HubConnection;
users$ = new BehaviorSubject([]);

constructor() {
this.startConnection();
}

public startConnection = () => {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl('https://localhost:44316/user')
.build();
this.hubConnection
.start()
.then(() => console.log('Connection started'))
.catch(err => console.log('Error while starting connection: ' + err));
}

public notifyAdmin = () => {
this.hubConnection.on('notifyAdmin', (data) => {
this.users$.next(data.split(','));
console.log('notify admin:', data);
});
}

public userPing( userName): void {
if (this.hubConnection.state === signalR.HubConnectionState.Connected){
this.hubConnection
.invoke('UserRegister', userName)
.catch(err => console.error('userPing error:', err));
}
}
}

The service also has the userPing function that invokes the userRegister interface in SignalR hubconnection. This function is called in the waitingroom Angular component, so the server will be aware that the user is active on the page.

WaitingRoom.Component.ts

Finally, the notifyAdmin function will subscribe the notifyAdmin event in the SingalR server and accept the data stream into the users$ observable. The observable is bound into UI with async pipe, so the change of the connected users is showing in real time!

Conclusion

The beauty of SignalR is in its simplicity, robustness, and efficiency.

The source code of the Angular sample project can be found here , and the .Net Project is here .

Notes: Recently, I re-implemented this solution using NestJS and Socket.IO, check it out.

Happy Programming.

  • Title: Detect active users in a page using SignalR and Angular
  • Author: Sunny Sun
  • Created at : 2020-04-07 00:00:00
  • Updated at : 2024-08-16 19:46:17
  • Link: http://coffeethinkcode.com/2020/04/07/detect-active-users-using-siganlr-and-angular/
  • License: This work is licensed under CC BY-NC-SA 4.0.
On this page
Detect active users in a page using SignalR and Angular