Getting started with SignalR using ASP.NET Core and Angular

This article shows how to setup a first SignalR Hub in ASP.NET Core 2.0 and use it with an Angular client. SignalR will be released with dotnet 2.1. Thanks to Dennis Alberti for his help in setting up the code example.

Code: https://github.com/damienbod/AspNetCoreAngularSignalR

Posts in this series

History

2018-05-08 Updated Microsoft.AspNetCore.SignalR 2.1 rc1
2018-03-14 Updated Microsoft.AspNetCore.SignalR 1.0.0-preview1-final, Angular 5.2.8, @aspnet/signalr 1.0.0-preview1-update1
2017-11-05 Updated to Angular 5 and Typescript 2.6.1, SignalR 1.0.0-alpha2-final
2017-09-15: Updated @aspnet/signalr-client to use npm feed, and 1.0.0-alpha1-final

The required SignalR Nuget packages and npm packages are at present hosted on MyGet. Your need to add the SignalR packagesto the csproj file. To use the MyGet feed, add the https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json to your package sources.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <TypeScriptToolsVersion>2.8</TypeScriptToolsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0-rc1-final" />
    <PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-rc1-final" />
    <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="1.0.0-rc1-final" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.0-rc1-final" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0-rc1-final" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.0-rc1-final" PrivateAssets="All" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
    <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" />
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Dtos\Dtos.csproj" />
  </ItemGroup>
</Project>

Now create a simple default hub.

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

namespace AspNetCoreSignalr.SignalRHubs
{
    public class LoopyHub : Hub
    {
        public Task Send(string data)
        {
            return Clients.All.SendAsync("Send", data);
        }
    }
}

Add the SignalR configuration in the startup class. The hub which was created before needs to be added in the UseSignalR extension method.

public void ConfigureServices(IServiceCollection services)
{
	...
	services.AddSignalR();
	...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
	...

	app.UseSignalR(routes =>
	{
		routes.MapHub<LoopyHub>("/loopy");
	});

	...
}

Setup the Angular application. The Angular application is setup using a wepback build and all dependencies are added to the packages.json file.

You can use the The MyGet npm feed if you want to use the aspnetcore-ci-dev. You can do this using a .npmrc file in the project root. Add the registry path. If using the npm package, do not add this.

@aspnet:registry=https://dotnet.myget.org/f/aspnetcore-ci-dev/npm/

Now add the required SignalR npm packages to the packages.json file. Using the npm package from NuGet:

 "dependencies": {
    "@ngrx/effects": "6.0.0-beta.1",
    "@ngrx/store": "6.0.0-beta.1",
    "@ngrx/store-devtools": "6.0.0-beta.1",
    "@aspnet/signalr": "1.0.0-rc1-update1",
    "bootstrap": "3.3.7",
    "@angular/animations": "6.0.0",
    "@angular/common": "6.0.0",
    "@angular/compiler": "6.0.0",
    "@angular/compiler-cli": "6.0.0",
    "@angular/core": "6.0.0",
    "@angular/forms": "6.0.0",
    "@angular/http": "6.0.0",
    "@angular/platform-browser": "6.0.0",
    "@angular/platform-browser-dynamic": "6.0.0",
    "@angular/platform-server": "6.0.0",
    "@angular/router": "6.0.0",
    "@angular/upgrade": "6.0.0",
    "@angular-devkit/core": "0.6.0",
    "core-js": "2.5.5",
    "ie-shim": "0.1.0",
    "msgpack5": "4.0.2",
    "rxjs": "6.1.0",
    "rxjs-compat": "6.1.0",
    "zone.js": "0.8.26"
  },

Add the SignalR client code. In this basic example, it is just added directly in a component. The sendMessage funtion sends messages and the hubConnection.on function receives all messages including its own.

import { Component, OnInit } from '@angular/core';
import { HubConnection } from '@aspnet/signalr';
import * as signalR from '@aspnet/signalr';

@Component({
    selector: 'app-home-component',
    templateUrl: './home.component.html'
})

export class HomeComponent implements OnInit {
    private _hubConnection: HubConnection | undefined;
    public async: any;
    message = '';
    messages: string[] = [];

    constructor() {
    }

    public sendMessage(): void {
        const data = `Sent: ${this.message}`;

        if (this._hubConnection) {
            this._hubConnection.invoke('Send', data);
        }
        this.messages.push(data);
    }

    ngOnInit() {
        this._hubConnection = new signalR.HubConnectionBuilder()
            .withUrl('https://localhost:44324/loopy')
            .configureLogging(signalR.LogLevel.Information)
            .build();

        this._hubConnection.start().catch(err => console.error(err.toString()));

        this._hubConnection.on('Send', (data: any) => {
            const received = `Received: ${data}`;
            this.messages.push(received);
        });
    }
}

The messages are then displayed in the component template.

<div class="container-fluid">

    <h1>Send some basic messages</h1>


    <div class="row">
        <form class="form-inline" (ngSubmit)="sendMessage()" #messageForm="ngForm">
            <div class="form-group">
                <label class="sr-only" for="message">Message</label>
                <input type="text" class="form-control" id="message" placeholder="your message..." name="message" [(ngModel)]="message" required>
            </div>
            <button type="submit" class="btn btn-primary" [disabled]="!messageForm.valid">Send SignalR Message</button>
        </form>
    </div>
    <div class="row" *ngIf="messages.length > 0">
        <div class="table-responsive">
            <table class="table table-striped">
                <thead>
                    <tr>
                        <th>#</th>
                        <th>Messages</th>
                    </tr>
                </thead>
                <tbody>
                    <tr *ngFor="let message of messages; let i = index">
                        <td>{{i + 1}}</td>
                        <td>{{message}}</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    <div class="row" *ngIf="messages.length <= 0">
        <span>No messages</span>
    </div>
</div>

Now the first really simple SignalR Hub is setup and an Angular client can send and receive messages.

Links:

https://github.com/aspnet/SignalR#readme

https://www.npmjs.com/package/@aspnet/signalr-client

https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json

https://dotnet.myget.org/F/aspnetcore-ci-dev/npm/

https://dotnet.myget.org/feed/aspnetcore-ci-dev/package/npm/@aspnet/signalr-client

https://www.npmjs.com/package/msgpack5

Advertisements

25 comments

  1. […] Getting started with SignalR using ASP.NET Core and Angular (Damien Bowden) […]

  2. Nice and simple write up thanks. Would be great to see one similar for React. Anyone?

  3. […] Getting started with SignalR using ASP.NET Core and Angular – Damien Bowden […]

  4. hi damienbod
    Would you like to write asp.net core 2 binding collections with non-sequential indices, add an item and remote an item in razor page?

    1. sounds interesting, greetings Damien

  5. Elibariki Muna · · Reply

    I am using systemjs and would like to see the configuration for this to work

    1. +1. I also use systemjs.

  6. Branislav Petrovic · · Reply

    Hi Damien,

    I tested this sample with dev and prod webpack configuration. Both applications work fine in Chrome, Firefox and Opera, but doesn’t work in Safari-desktop (SyntaxError: Unexpected token ‘const’) and IE11 (Syntax error, class keyword is problem in syntax). I figured out that this is ES6 problem, because latter browsers doesn’t support some ES6 features.

    I include Babel in webpack configuration with transform-runtime plugin and es2015 preset, and this doesn’t transpile problematic ES6 code to ES5. I’ll be grateful if you have any tip on this issue.

    BR,
    Branislav

    1. Hi Branislav, thanks for this info, I never tested in Safari, IE11 should work. I test this and let you know what if find, (As soon as I get time, very busy with the day job)

      Greetings Damien

  7. […] For more information here […]

  8. In the demo it says @angular/platform-server unavailable 😦

    1. npm install, npm run build-production, does this work?

      Greetings Damien

  9. i am getting error like Transports.js:28 WebSocket connection to ‘ws://localhost:51383/chat?id=95976d32-4361-411e-aa5f-cca73f352cef’ failed: Error during WebSocket handshake: Unexpected response code: 204

    1. If you are running the SignalR application on Windows 7 using IIS Express, try running the application using Kestrel instead.

  10. I keep getting Error: Failed to start the connection. SyntaxError: Unexpected token < in JSON at position 0

  11. I’m getting this error: Failed to load http://localhost:49888/signalr: Method OPTIONS is not allowed by Access-Control-Allow-Methods in preflight response.
    I have already enabled all sorts of CORS and none fix the issue.

    1. Are the options request disabled on the Web server?

  12. Guess Whover · · Reply

    Can SignalR be used to update data that’s already on the screen? E.g. user A is looking at a list of two products and their prices (Product A: $1, Product B: $2). User B updates the price of Product A to $3. Is there a way to push that update to all users, so that they see Product A: $3 ?

  13. […] Getting started with SignalR using ASP.NET Core and Angular […]

  14. Kaushik · · Reply

    Good blog, In production server getting an error “, cannot send data if the connection is not in the ‘Connected’ State”

    Connection make successfully, but after sometimes the connection is closed and it generates above error

  15. hello , i was following your steps but ,i have faced this error :
    “Error: Failed to start the connection: Error: Unable to initialize any of the available transports.”
    any ideas?

    1. nsteuver · · Reply

      Try updating to the newest version of the Angular client signalR package as well as the .NET Core signalR Nuget package. I ran into this error and found out I had the newest version of the client but not the .NET package.

  16. John · · Reply

    Apologies for very newbie question.
    Have compiled and run the app, get the indexpage displaying “Loading….”. Cannot see how to access the home page or any of the other news pages. All of the code looks correct compared to the examples above.
    In order to get my version running I needed to change the directory name of angularApp to wwwroot. I then also changed any other path reference to wwwroot.

  17. Hi,

    There is 2 times “this._hubConnection.start()” in ngInit, is it normal?

    Thank for your article,
    Cedric

    1. Hi Cédric, thanks, I’ll fix this, thanks for reporting,
      Greetings Damien

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

%d bloggers like this: