.Net WebApi - SignalR & Angular
Sample project demonstrating the bare minimum required to integrate SignalR with Angular.

Search for a command to run...
Sample project demonstrating the bare minimum required to integrate SignalR with Angular.

No comments yet. Be the first to comment.
Recently, I realized that I have a gaming laptop doing little more than gathering dust. It has an NVIDIA GeForce RTX 4060 with 8 GB of VRAM—sure, it’s not a monster, but it still seems a shame not to
Recently, I realized that I have a gaming laptop doing little more than gathering dust. It has an NVIDIA GeForce RTX 4060 with 8 GB of VRAM—sure, it’s not a monster, but it still seems a shame not to
Exam Buddy repository This project came about after a request from my wife. She needed a simple application to help her prepare for several exams using a known set of questions and answers. I saw it a
Based on the University of Maryland and Microsoft, the answer seems to be yes (tak). For details, see this paper. This is the earliest recorded sentence in the Polish language: Daj, niech ja pomielę,
myblog
4 posts
Code available at GitHub
Full documentation available here
SignalR acts as an abstraction layer over remote procedure calls (RPC), streamlining their use. It primarily employs the WebSocket network protocol, but can fallback to other transport protocols like HTML5 or Comet when necessary. A key concept in SignalR is the Hub, which facilitates communication between clients and the server, allowing clients to invoke server methods and vice versa. Hubs are transient, meaning they should not store state. To call methods outside a hub, IHubContext is used. SignalR supports strongly typed hubs, reducing the risk of runtime errors - there is no need to use strings for method names. Hubs can target all connected clients, specific connections, groups, or individual users. Additionally, SignalR integrates with ASP.NET Core authentication, associating users with each connection. Authentication data is accessible within the hub via HubConnectionContext.User, similar to WebApi.
Server side:
Client side:
JavaScript/TypeScript
.NET runs on ASP.NET Core
Java
Swift



Install SignalR NuGet package
Microsoft.AspNetCore.SignalR
Install SignalR npm package
npm install @microsoft/signalr
This section describes the application setup details related specifically to SignalR - surprisingly there is not much to do in scope of configuring the app. Things like CORS, HTTPS redirection, etc. are not covered here. For sake of the sample project simplicity the authorization concept was ignored.
Program.cs
// ...
// Add SignalR services
builder.Services.AddSignalR();
// ...
// Map incoming requests with a specific hub
app.MapHub<TasksHub>("/tasksHub");
app.Run();
// ...
webapi/Api/TasksApi.Core/TasksHub.cs
Contract for strongly typed Hub
public interface ITasksStatusClient
{
// Called on client-side by server
Task TasksStatuses(IReadOnlyCollection<TaskDto> tasks);
// Called on client-side by server
Task TaskStatus(TaskDto task);
// Called on server-side by clients
Task<int> RunningTasksCount(int tasksCount);
}
Hub implementation
public class TasksHub : Hub<ITasksStatusClient>
{
private readonly ITasksStatusService _taskStatusService;
// Task service injected into the Hub to fetch data from in-memory storage
public TasksHub(ITasksStatusService taskStatusService)
{
_taskStatusService = taskStatusService ?? throw new ArgumentNullException(nameof(taskStatusService));
}
// This method can be called by clients
public async Task<int> RunningTasksCount()
{
return await Task.FromResult(_taskStatusService.RunningTasksCount);
}
}
webapi/Api/TasksApi.Core/TasksStatusService.cs
Example of calling the method on client side
// Call method for all clients
public Task ExecuteTask(TaskDto task)
{
return ExecuteTaskInternal(task, (t) =>
_tasksStatusHubContext.Clients.All.TaskStatus(t));
}
// Call method only for specific connection (caller)
public Task ExecuteTask(TaskDto task, string connectionId)
{
return ExecuteTaskInternal(task, (t) =>
_tasksStatusHubContext.Clients.Client(connectionId).TaskStatus(t));
}
// Call method for all clients
public async Task RemoveTask(int id)
{
_taskStorage.Delete(id);
await _tasksStatusHubContext.Clients.All.TasksStatuses(_taskStorage.GetAll());
}
angular/src/app/services/signalR/tasks-signalr.service.ts
Build hub connection
constructor() {
this.hubConnection = new HubConnectionBuilder()
.withUrl(environment.signalRBaseUrl + "tasksHub")
.build();
}
Establish connection with hub, executed in root component under OnInit method.
public start() {
if (this.hubConnection == null) {
return;
}
// Start Hub connection
this.hubConnection
.start()
.then(() => {
console.log('Connected to tasks hub.');
// We can store connection ID to make further calls with response only for caller
this.connectionId = this.hubConnection.connectionId ?? '';
})
.catch(error => console.log('Tasks hub connection error: ' + error));
// Register hub method that can be called by server on client side
this.hubConnection.on('TasksStatuses', (tasks: TaskDto[]) => {
this.tasksStatusesSubject.next(tasks);
})
// Register hub method that can be called by server on client side
this.hubConnection.on('TaskStatus', (task: TaskDto) => {
this.taskStatusSubject.next(task);
});
}
Close connection to hun, executed in root component under OnDestroy method
public stop() {
if (this.hubConnection == null) {
return;
}
this.hubConnection.stop().then(() => {
console.log('Disconnected from tasks hub.');
});
}
Call method on service-side
public getRunningTasksCount(): Observable<number> {
return new Observable<number>((subscriber) => {
this.hubConnection
// Provide expected return type and method name
// See webapi/Api/TasksApi.Core/TasksHub.cs for Hub contract
.invoke<number>('RunningTasksCount')
.then((count) => {
subscriber.next(count);
subscriber.complete();
})
.catch((err) => {
subscriber.error(err);
});
});
}