Tutorial: Get started with SignalR on ASP.NET Core

This tutorial teaches the basics of building a real-time app using SignalR. You learn how to:

  • Create a web app that uses SignalR on ASP.NET Core.
  • Create a SignalR hub on the server.
  • Connect to the SignalR hub from JavaScript clients.
  • Use the hub to send messages from any client to all connected clients.

At the end you'll have a working chat app:

SignalR sample app

View or download sample code (how to download).

Prerequisites

Create the project

  • From the menu, select File > New Project.

  • In the New Project dialog, select Installed > Visual C# > Web > ASP.NET Core Web Application. Name the project SignalRChat.

    New Project dialog in Visual Studio

  • Select Web Application to create a project that uses Razor Pages.

  • Make sure that the target framework is ASP.NET Core 2.1, and then select OK.

    New Project dialog in Visual Studio

Add the SignalR client library

The SignalR server library is included in the Microsoft.AspnetCore.App metapackage. But you have to get the JavaScript client library from npm, the Node.js package manager.

  • In Package Manager Console (PMC), change to the project folder (the one that contains the SignalRChat.csproj file).

    cd SignalRChat
    
  • Run the npm initializer to create a package.json file:

    npm init -y
    

    The command creates output similar to the following example:

    Wrote to C:\tmp\SignalRChat\package.json:
    {
      "name": "SignalRChat",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"0
    }
    
  • Install the client library package:

    npm install @aspnet/signalr
    

    The command creates output similar to the following example:

    npm notice created a lockfile as package-lock.json. You should commit this file.
    npm WARN signalrchat@1.0.0 No description
    npm WARN signalrchat@1.0.0 No repository field.
    
    + @aspnet/signalr@1.0.2
    added 1 package in 0.98s
    

The npm install command downloaded the JavaScript client library to a subfolder under node_modules. Copy it from there to a folder under wwwroot that you can reference from the chat app web page.

  • Create a signalr folder in wwwroot/lib.

  • Copy the signalr.js file from *node_modules/@aspnet/signalr/dist/browser* to the new wwwroot/lib/signalr folder.

Create the SignalR hub

A hub is a class that serves as a high-level pipeline that handles client-server communication.

  • In the SignalRChat project folder, create a Hubs folder.

  • In the Hubs folder, create a ChatHub.cs file with the following code:

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

    The ChatHub class inherits from the SignalR Hub class. The Hub class manages connections, groups, and messaging.

    The SendMessage method can be called by any connected client. It sends the received message to all clients. SignalR code is asynchronous to provide maximum scalability.

Configure the project to use SignalR

The SignalR server must be configured to pass SignalR requests to SignalR.

  • Add the following highlighted code to the Startup.cs file.

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    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; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                    options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });
    
    
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    
                services.AddSignalR();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            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.UseSignalR(routes =>
                {
                    routes.MapHub<ChatHub>("/chatHub");
                });
                app.UseMvc();
            }
        }
    }
    

    These changes add SignalR to the the dependency injection system and the middleware pipeline.

Create the SignalR client code

  • Replace the content in Pages\Index.cshtml with the following:

    @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>
    

    The preceding code:

    • Creates text boxes for name and message text, and a submit button.
    • Creates a list with id="messagesList" for displaying messages that are received from the SignalR hub.
    • Includes script references to SignalR and the chat.js application code that you create in the next step.
  • In the wwwroot/js folder, create a chat.js file with the following code:

    "use strict";
    
    var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
    
    connection.on("ReceiveMessage", function (user, message) {
        var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
        var encodedMsg = user + " says " + msg;
        var li = document.createElement("li");
        li.textContent = encodedMsg;
        document.getElementById("messagesList").appendChild(li);
    });
    
    connection.start().catch(function (err) {
        return console.error(err.toString());
    });
    
    document.getElementById("sendButton").addEventListener("click", function (event) {
        var user = document.getElementById("userInput").value;
        var message = document.getElementById("messageInput").value;
        connection.invoke("SendMessage", user, message).catch(function (err) {
            return console.error(err.toString());
        });
        event.preventDefault();
    });
    

    The preceding code:

    • Creates and starts a connection.
    • Adds to the submit button a handler that sends messages to the hub.
    • Adds to the connection object a handler that receives messages from the hub and adds them to the list.

Run the app

  • Press CTRL+F5 to run the app without debugging.
  • Copy the URL from the address bar, open another browser instance or tab, and paste the URL in the address bar.

  • Choose either browser, enter a name and message, and select the Send button.

    The name and message are displayed on both pages instantly.

    SignalR sample app

Tip

If the app doesn't work, open your browser developer tools (F12) and go to the console. You might see errors related to your HTML and JavaScript code. For example, suppose you put signalr.js in a different folder than directed. In that case the reference to that file won't work and you'll see a 404 error in the console. signalr.js not found error

Next steps

If you want clients to connect to a SignalR app from different domains, you have to enable Cross-Origin Resource Sharing (CORS). For more information, see Cross-origin resource sharing.

To learn more about SignalR, hubs, and JavaScript clients, see these resources: