Server asynchronous notifications
.NET Core Asynchronous C# SignalR SignalR Hub Visual Studio

How to Create SignalR Hubs within ASP.NET Core

Welcome to today’s post.

I will discuss how to use SignalR Hubs with ASP.NET Core. Before I explain what SignalR Hubs are.

I will explain what SignalR is and how useful it can be for certain types of applications.

I will also explain how to create a SignalR Hub from the Visual Studio development environment, including how to install the SignalR NuGet libraries.

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

Installing SignalR Libraries

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.

Configuring SignalR in .NET Core

To configure SignalR in an ASP.NET Core application, we begin with Startup.cs and 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.

Creating a SignalR Hub Server Class

The SignalR Hub server class, BookLoanHub contains methods that allow it to transmit data from the hub to connected SignalR clients. It is injected into the timed hosted service class that will periodically trigger a task that reads updated books, then transmits data back to connected SignalR clients.

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:

Signalr hub

Creating a Scheduled Hosted Timer Service

As I mentioned, the SignalR Hub can be hosted within a hosted service that is triggered by a background timer task. An example of how we implement background tasks within hosted services is in my previous post.  

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();
     }
   }
}

The segment of code within the DoWork() method of the TimedHostedService class that is triggered from the timer task gets a list of book record changes, then transmits those to SignalR clients that are connected to the SignalR Hub.

For the hosted service to run within .NET Core, it needs to be added to the services collection from within ConfigureServices(), which can be done as shown:  

services.AddHostedService<TimedHostedService>();

Enabling SignalR Client Connectivity

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.

The above implementation and walkthrough demonstrate how to create and setup a SignalR Hub, ready to push notifications back to connected SignalR clients. In the next post I will show how to implement a basic SignalR client from a front-end web application that connects to the SignalR Hub.

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.

Social media & sharing icons powered by UltimatelySocial