Get started with SignalR on ASP.NET Core

By Rachel Appel

This tutorial teaches the basics of building a real-time app using SignalR for ASP.NET Core.

Solution

This tutorial demonstrates the following SignalR development tasks:

  • Create a SignalR on ASP.NET Core web app.
  • Create a SignalR hub to push content to clients.
  • Modify the Startup class and configure the app.

View or download sample code (how to download)

Prerequisites

Install the following software:

Create an ASP.NET Core project that hosts SignalR client and server

  1. Use the File > New Project menu option and choose ASP.NET Core Web Application. Name the project SignalRChat.

    New Project dialog in Visual Studio

  2. Select Web Application to create a project using Razor Pages. Then select OK. Be sure that ASP.NET Core 2.1 is selected from the framework selector, though SignalR runs on older versions of .NET.

    New Project dialog in Visual Studio

Visual Studio includes the Microsoft.AspNetCore.SignalR package containing its server libraries as part of its ASP.NET Core Web Application template. However, the JavaScript client library for SignalR must be installed using npm.

  1. Run the following commands in the Package Manager Console window, from the project root:

    npm init -y
    npm install @aspnet/signalr
    
  2. Create a new folder named "signalr" inside the lib folder in your project. Copy the signalr.js file from node_modules\@aspnet\signalr\dist\browser to this folder.

Create the SignalR Hub

A hub is a class that serves as a high-level pipeline that allows the client and server to call methods on each other.

  1. Add a class to the project by choosing File > New > File and selecting Visual C# Class. Name the class ChatHub and the file ChatHub.cs.

  2. Inherit from Microsoft.AspNetCore.SignalR.Hub. The Hub class contains properties and events for managing connections and groups, as well as sending and receiving data.

  3. Create the SendMessage method that sends a message to all connected chat clients. Notice it returns a Task, because SignalR is asynchronous. Asynchronous code scales better.

    using Microsoft.AspNetCore.SignalR;
    using System.Threading.Tasks;
    
    namespace SignalRChat.Hubs
    {
        public class ChatHub : Hub
        {
            public async Task SendMessage(string user, string message)
            {
                await Clients.All.SendAsync("ReceiveMessage", user, message);
            }
        }
    }
    

Configure the project to use SignalR

The SignalR server must be configured so that it knows to pass requests to SignalR.

  1. To configure a SignalR project, modify the project's Startup.ConfigureServices method.

    services.AddSignalR makes the SignalR services available to the dependency injection system.

  2. Configure routes to your hubs with UseSignalR in the Configure method. app.UseSignalR adds SignalR to the middleware pipeline.

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using SignalRChat.Hubs;
    
    namespace SignalRChat
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });
    
                services.AddMvc();
    
                services.AddCors(options => options.AddPolicy("CorsPolicy",
                builder =>
                {
                    builder.AllowAnyMethod().AllowAnyHeader()
                           .WithOrigins("http://localhost:55830")
                           .AllowCredentials();
                }));
    
                services.AddSignalR();
            }
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
    
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                    app.UseHsts();
                }
    
                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseCookiePolicy();
                app.UseCors("CorsPolicy");
                app.UseSignalR(routes =>
                {
                    routes.MapHub<ChatHub>("/chatHub");
                });
                app.UseMvc();
            }
        }
    }
    

Create the SignalR client code

  1. Add a JavaScript file, named chat.js, to the wwwroot\js folder. Add the following code to it:

    // The following sample code uses modern ECMAScript 6 features 
    // that aren't supported in Internet Explorer 11.
    // To convert the sample for environments that do not support ECMAScript 6, 
    // such as Internet Explorer 11, use a transpiler such as 
    // Babel at http://babeljs.io/. 
    //
    // See Es5-chat.js for a Babel transpiled version of the following code:
    
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/chatHub")
        .build();
    
    connection.on("ReceiveMessage", (user, message) => {
        const msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
        const encodedMsg = user + " says " + msg;
        const li = document.createElement("li");
        li.textContent = encodedMsg;
        document.getElementById("messagesList").appendChild(li);
    });
    
    connection.start().catch(err => console.error(err.toString()));
    
    document.getElementById("sendButton").addEventListener("click", event => {
        const user = document.getElementById("userInput").value;
        const message = document.getElementById("messageInput").value;
        connection.invoke("SendMessage", user, message).catch(err => console.error(err.toString()));
        event.preventDefault();
    });
    
    
  2. Replace the content in Pages\Index.cshtml with the following code:

    @page
        <div class="container">
            <div class="row">&nbsp;</div>
            <div class="row">
                <div class="col-6">&nbsp;</div>
                <div class="col-6">
                    User..........<input type="text" id="userInput" />
                    <br />
                    Message...<input type="text" id="messageInput" />
                    <input type="button" id="sendButton" value="Send Message" />
                </div>
            </div>
            <div class="row">
                <div class="col-12">
                    <hr />
                </div>
            </div>
            <div class="row">
                <div class="col-6">&nbsp;</div>
                <div class="col-6">
                    <ul id="messagesList"></ul>
                </div>
            </div>
        </div>
        <script src="~/lib/signalr/signalr.js"></script>    
        <script src="~/js/chat.js"></script>
        @*<script src="~/js/es5-chat.js"></script>*@
    

    The preceding HTML displays name and message fields, and a submit button. Notice the script references at the bottom: a reference to SignalR and chat.js.

Run the app

  1. Select Debug > Start without debugging to launch a browser and load the website locally. Copy the URL from the address bar.

  2. Open another browser instance (any browser) and paste the URL in the address bar.

  3. Choose either browser, enter a name and message, and click the Send button. The name and message are displayed on both pages instantly.

Solution

Introduction to ASP.NET Core SignalR