Broadcasting with SignalR and .NET Core

August 11, 2020
Written by
Reviewed by

Boradcasting with SignalR and .NET Core

SignalR is a library for .NET developers for adding real-time web functionality to applications. It is often used for real-time chat applications but is also great for live dashboards and games!

SignalR takes advantage of several transports, automatically selecting the best available transport given the client and server's capabilities. SignalR uses WebSockets under the hood when available, and gracefully falls back to other techniques and technologies when it isn't.

I've recently been working with Twitch chatbots and wanted to use SignalR to update browser scenes based on commands sent in via my viewers.

This meant that I would need to call a SignalR broadcast from a different project.

This blog will share how to do that.

If you would like to see my completed project, it's available on my GitHub here.

What you'll need:

  • A basic knowledge of ASP.NET Core
  • .NET Core 3.1 installed
  • An IDE such as Visual Studio, JetBrains Rider or VS Code
  • Postman or similar for testing API calls

What you'll know by the end of this blog:

  • How to add SignalR to an ASP.NET Core application
  • How to broadcast a message to all clients from an API call
  • How to broadcast to all clients from a different project

If you would like to see a full integration of Twilio APIs in a .NET Core application then checkout this free 5-part video series I created. It's separate from this blog post tutorial but will give you a full run down of many APIs at once.

Getting started

Getting started with SignalR is well documented. I followed a tutorial on the Microsoft documentation, and I suggest you do too. This tutorial creates a Razor Pages application, but you could totally do this with an MVC application. A note: be sure to create an empty solution and add the new SignalR project to this solution. I named my web application "BroadcastingSignalR.Web" so my namespacing will reflect this.

You'll see that you can have two browsers open and when you send a message on one, it updates the other.

Behind the scenes, SignalR is sending the incoming message from one client out to all the other clients. However, we can trigger the update manually from a REST API.

Create an API endpoint

We will need an API endpoint to broadcast our message to. Create a Controllers Directory in the root and add a new Controller called BroadcastController to it.

Replace all the template code with the code below:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using SignalRChat.Hubs;

namespace WebApplication.Controllers
{
   [ApiController]
   [Route("api/broadcast")]
   public class BroadcastController : ControllerBase
   {
       private readonly IHubContext<ChatHub> _hub;
      
       public BroadcastController(IHubContext<ChatHub> hub)
       {
           _hub = hub;
       }
      
       [HttpGet]
       public async Task Get(string user, string message)
       {
           await _hub.Clients.All.SendAsync("ReceiveMessage", user, message);
       }
   }
}

If you created a Razor Pages application as in the Microsoft tutorial, you will need to add in some middleware to get it to work. Open the "Startup.cs"  and add the following two lines of code.  Note that if you are modifying an MVC application, then you may already have the middleware included.

 
/// omitted for brevity

       // This method gets called by the runtime. Use this method to add services to the container.
       public void ConfigureServices(IServiceCollection services)
       {
           services.AddSignalR();
           services.AddControllers();
           services.AddRazorPages();
       }

       // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
       public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
       {
           if (env.IsDevelopment())
           {
               app.UseDeveloperExceptionPage();
           }
           else
           {
               app.UseExceptionHandler("/Error");
               app.UseHsts();
           }

           app.UseHttpsRedirection();
           app.UseStaticFiles();

           app.UseRouting();

           app.UseAuthorization();

           app.UseEndpoints(endpoints =>
           {
               endpoints.MapRazorPages();
               endpoints.MapControllers();
               endpoints.MapHub<ChatHub>("/chathub");
           });
       }
   }
}

Now we can test the endpoint! Run the application, open up two browsers and test that it's still working as demonstrated in the Microsoft tutorial.

Open Postman and make a call to the API, adding in user and message as URL parameters.

Your request will look something like this:

http://localhost:18128/api/broadcast?user=layla&message=hello!

My app is running on port 18128, yours might be different. You can check in Properties/launchSettings.json. You may also want to change the launch URL from 5000/5001 to something else if you encounter self-cert issues.

You should then see an update appear in your browser 🎉.

gif of postman making an api call and the message showing in the browser

Broadcasting from a different project

To link my SignalR project to my Twitch chatbot I need to call the SignalR hub from within a console app.

We need to add a console project to our solution alongside the SignalR web project.

You can right click on the solution and add a console app.

screenshot of where the new project menu is

You can add it from the CLI using the following command from within the solution directory:

>dotnet new console -n Agent

I've named it Agent to prevent any naming conflicts with 'Console'.

The console application will need to reference the webapp. Right click on the web project and select 'Add > Project Reference...'. Then select the Web application and click okay.

screenshot of where the add reference menu is

You can manually add a reference to the console '.csproj' file by adding the following line:

 
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\WebApplication\BroadcastingSignalR.Web.csproj" />
  </ItemGroup>

</Project>

The path and/or name of your web project may be different so ensure you update the above.


The console application will also need some awareness of SignalR so add in the NuGet package "Microsoft.AspNetCore.SignalR.Client" via the package manager, CLI or by adding it to the '.csproj' as shown below.

 
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.6" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\WebApplication\BroadcastingSignalR.Web.csproj" />
  </ItemGroup>

</Project>



Now that we have the reference to the web app and the SignalR package, we can update the 'Program.cs' file in the console app with the code below:

 
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;

namespace Agent
{
   class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var connection = new HubConnectionBuilder()
                .WithUrl("http://localhost:<WEB APP PORT>/ChatHub")
                .WithAutomaticReconnect()
                .Build();

await connection.StartAsync();
        }
    }
}

The code above defines the connection to the hub, giving it the URL of the web application. You can find out which port your web app is running on by looking in "Properties/launchSettings.json" on the root of the web app.

Our SignalR hub is now ready to use. We'll just call it directly in Program to demonstrate.

Add the following code to the "Program.cs" in the Console application.

 
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;

namespace Agent
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            HubConnection connection = new HubConnectionBuilder()
                .WithUrl("http://localhost:18128/ChatHub")
                .WithAutomaticReconnect()
                .Build();

            await connection.StartAsync();

            string message = Console.ReadLine();

            await connection.InvokeAsync("SendMessage", "Agent", message);

        }
     
    }
}


Testing it out

We'll need to run both applications simultaneously. To do so follow the instructions here if using Visual Studio or you can use dotnet run on each project from separate command line windows (or tabs if your command line tool supports them!).

Open two separate browser windows, both to the localhost URL of the web app. Send a message from one of the windows and you should see the second one update just as before.

Now from the command line of the console application, enter a message. You'll see both browser tabs update with a message from the "Agent".

gif of sending a mesage in the console and it appearing in the browser

What next

We've successfully broadcast to a web app from an API endpoint and a console application using SignalR, but what can you do next?

Apart from the obvious chat uses such as chat and dashboards, I use SignalR for chat activated overlays on Twitch. Whether that's making it rain puppy heads or playing sounds!

Feel free to check out my twitch bot, albeit a work in progress or join me on Twitch to see it in action!

And if you fancy combining SignalR and Twilio then check out this blog series by Twilio Champion, Jim McG.

If you have any cool ideas or use cases for SignalR, then I would love to hear from you!