SignalR with Angular 10 and ASP.NET

Viewed 8572

I am trying to implement SignalR in an ASP.NET (not Core) and Angular (currently 10) application. Startup.cs is using Owin.

Every documentation or example I could find was for either ASP.NET Core or wasn't using Angular so could someone point me in a good direction?

The closest I could find for this combo was this guide: https://www.c-sharpcorner.com/article/asp-net-signalr-angular2-and-typescript-real-time-clock/, however I keep getting "Cannot read property 'hubConnection' of undefined" error, probably because I don't understand what '$' is doing in the SignalRService class since I started working with Angular 7 and above.

Any help would be very appreciated.

3 Answers

U can use the example in this link SignalR using Angular 10

Steps:

  1. Install the needed signalr library

npm i @microsoft/signalr@latest --save

  1. Import the needed classes

import { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';

  1. Connect to hub
this._hubConnection = new HubConnectionBuilder()
  .withUrl('http://localhost:52864/chathub')
  .build();
  1. Listen to methods on the hub
this._hubConnection.on('MessageReceived', (message) => {
  console.log(message);
});
  1. Start the connection
this._hubConnection.start()
  .then(() => console.log('connection started'))
  .catch((err) => console.log('error while establishing signalr connection: ' + err));

How the dummy example looks like:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';

@Component({
  selector: 'app-messaging',
  templateUrl: './messaging.component.html',
  styleUrls: ['./messaging.component.scss']
})
export class MessagingComponent implements OnInit {
  private _hubConnection: HubConnection;

  constructor(private _httpClient: HttpClient) { }

  ngOnInit(): void {
    this.connect();
  }

  public onSendButtonClick(): void {
    this._hubConnection.send('SendMessage', 'test message').then(r => { });
  }

  private connect(): void {
    this._hubConnection = new HubConnectionBuilder()
      .withUrl('http://localhost:52864/chathub')
      .build();

    this._hubConnection.on('MessageReceived', (message) => {
      console.log(message);
    });

    this._hubConnection.start()
      .then(() => console.log('connection started'))
      .catch((err) => console.log('error while establishing signalr connection: ' + err));
  }
}

Note: no need to install the 'signalr-protocol-msgpack'

The old (not core) SignalR javascript client depends on jQuery. So the best way to add support for SignalR in your angular app is first

  1. Add jquery and signalr npm packages to your project

    npm install jquery signalr --save

  2. Add @types/jquery and @types/signalr npm packages for typing support for both packages.

    npm install @types/jquery @types/signalr --save-dev

  3. Edit your angular.json file projects/[projectname]/architect/build/scripts node to include both jquery and signalr scripts (See example for full file below)

    "scripts": [ "./node_modules/jquery/dist/jquery.min.js", "./node_modules/signalr/jquery.signalR.js" ]

  4. Edit tsconfig.app.json file and add "jquery","signalr" to the "compilerOptions"/"types" list. (see example for full file below)

Here is how angular.json should look like (project name here is signalr demo)

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "signalrdemo": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/signalrdemo",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": [
              "./node_modules/jquery/dist/jquery.min.js",
              "./node_modules/signalr/jquery.signalR.js"
            ]
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "signalrdemo:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "signalrdemo:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "signalrdemo:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "signalrdemo:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "signalrdemo:serve:production"
            }
          }
        }
      }
    }},
  "defaultProject": "signalrdemo"
}

Here is how tsconfig.app.json should look like:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": ["jquery","signalr"]
  },
  "files": [
    "src/main.ts",
    "src/polyfills.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}
Related