Welcome to today’s post.
I will discuss how to use SignalR with .NET Core.
What is SignalR?
SignalR is an open-source library that makes it easier to implement real-time server to client push notifications. Essentially these are remote procedure (RPC) calls.
Examples of uses for SignalR include:
- Mapping or GPS apps that require data updates from servers.
- Dashboards that require updates to stock quantities or service calls.
- Apps that require notifications such as messages or sales orders.
- A chat service with messaging between clients or to servers and broadcast messaging.
SignalR APIs can be used to create RPC’s to call JavaScript functions on clients from .NET Code.
The main features of SignalR include:
- Automatic connection management.
- Simultaneous message delivery to connected clients.
- Message recipients can be individuals or groups.
- Scalable for increasing traffic.
SignalR uses Hubs to communicate between server and clients. SignalR Hubs are a pipeline that allows clients to send messages to the hub. Server hubs can also send messages to individual clients or to groups of clients connected to the server hub.
Creating a SignalR Hub.
Before we can use SignalR in a client application, we will need to build a SignalR hub.
This is done in Visual Studio 2017 as follows:
Create a Web API application from the Web Application .NET Core template.
The instructions below are for .NET Core 2.1. I will explain where the changes for 2.2 are applicable. Install the SignalR NuGet package.

In our Startup.cs make the following additions:
Include the namespace:
using Microsoft.AspNetCore.SignalR;
In ConfigureServices() add the SignalR middleware:
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
}
For .NET Core 2.2 you will need to set the compatibility level to 2.1 as shown:
services.AddMvc()
.SetCompatibilityVersion(
Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
In Configure() method add the following application pipeline:
app.UseSignalR(routes =>
{
routes.MapHub<BookLoanHub>("/bookloanHub");
});
This route will then be visible to any SignalR clients that wish to communicate with the Hub.
Create a Hub server class
using System;
using HubServiceInterfaces;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace Server
{
public class BookLoanHub: Hub<IBookLoanChange>
{
public async Task SendBookCatalogChanges(
int numberBookLoanChanges)
{
await Clients
.All
.SendBookCatalogChanges(numberBookLoanChanges);
}
}
}
The Hub connection can be hosted within a hosted service and triggered by a timer.
A commonly used architecture is the SignalR hub service transmitting messages to clients who then act on these messages. An example may be a dashboard report within an application:

The hosted timer service is implemented as shown:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Server;
using HubServiceInterfaces;
using BookLoan.Services;
using BookLoan.Models;
namespace BackgroundTasksSample.Services
{
internal class TimedHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
private readonly IBookService _bookService;
private readonly IHubContext<BookLoanHub, IBookLoanChange>
_bookLoanHub;
public TimedHostedService(ILogger<TimedHostedService> logger,
IHubContext<BookLoanHub, IBookLoanChange> bookLoanHub,
IBookService bookService)
{
_logger = logger;
_bookLoanHub = bookLoanHub;
_bookService = bookService;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(60));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
List<BookViewModel> list = _bookService
.GetChangedBooksList()
.GetAwaiter()
.GetResult();
int numberBooks = list.ToArray().Length;
_logger.LogInformation(String.Format(
"Number of new books {0}", numberBooks));
_bookLoanHub.Clients.All.SendBookCatalogChanges(numberBooks);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation(
"Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
}
In ConfigureServices() configure the hosted timer service class as shown:
services.AddHostedService<TimedHostedService>();
To allow clients that are from a different domain to receive or send messages from our hub we must enable cross-origin resource sharing (CORS). We do this by adding the following code into ConfigureServices() as shown:
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.WithOrigins("http://localhost:4200")
.AllowCredentials();
}));
The above will allow communication with an Angular client on local port 4200.
Into Configure() add the following:
app.UseCors("CorsPolicy");
When run the console will start the SignalR service hub on port 5000:

On regular intervals the timer background task will awake and call an API to complete a task:

All connected SignalR clients will be notified after the results of the call.
That’s all for today’s post.
I hope you found this post useful and informative.
In the next post I will show how the calls can be consumed by a SignalR client.

Andrew Halil is a blogger, author and software developer with expertise of many areas in the information technology industry including full-stack web and native cloud based development, test driven development and Devops.