SignalR with Angular 10 and ASP.NET
Asked Answered
T

4

8

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.

Tuttle answered 10/8, 2020 at 15:4 Comment(2)
<script src="../Scripts/jquery.signalR.js" type="text/javascript"></script> there does the $ come fromTrek
You are more likely to get a useful answer if you narrow this down to a specific question, possibly with a minimal code example. Asking generally, how do I. get SignalR to work with Angular 7 is just too broad and doesn't fit this format.Biamonte
O
10

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'

Officiate answered 4/11, 2020 at 5:27 Comment(1)
I don't know why this has more upvotes This doesn't work with ASP NET 4.5 OWINSnipe
C
3

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"
  ]
}
Carmen answered 10/8, 2020 at 15:35 Comment(4)
Hello @SherifElmetainy, thank you for answering. Unfortuantely, this did not resolve my issue completely. I'm still getting "Cannot read property 'hubConnection' of undefined" error in SignalRService class. Do you perhaps know how to tell that class the script exists? Tried adding the script to html file of the component I'm trying to use SignalR in, html of the parent where module.ts is and in the index.html file.Tuttle
No adding script to the HTML won't help. It needs to be added to angular.json. Cannot read property hubConnection of undefined means that the $ symbol is undefined, and this is defined by jquery. So the jquery script must be included, and the way to included it an an angular application is by adding it to angular.json scripts.Carmen
Sorry if I'm missing something obvious, I'm new to SignalR and jQuery in general. I've added the scripts to angular.json. If I use 'import * as $ from "jquery";' I get 'ERROR TypeError: jquery__WEBPACK_IMPORTED_MODULE_1__.hubConnection is not a function' and if I use 'var $: any;' I get the before mentioned unidentified error.Tuttle
I have the same issue. I am not sure if its something to do with Angular and strict mode, but unable to get through the error : Property 'connection' does not exist on type 'JQueryStatic'Maplemaples
C
1

I made the simple mistake of not declaring the jQuery symbol above the declaration of the Service:

declare var $: any;

e.g.

declare var $: any;  
@Injectable()  
export class SignalRService {  ...

This link on how to use jQuery with Angular clued me in:

https://blog.bitsrc.io/how-to-use-jquery-with-angular-when-you-absolutely-have-to-42c8b6a37ff9

Communist answered 21/3, 2022 at 22:13 Comment(0)
A
0

Signalr depends on jquery so first, you need to install

npm install signalr
npm install jquery

and their types

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

Add scripts to angular-cli.json

  "architect": {
    "build": {
      ...
      "options": {
        "scripts": [
          "node_modules/jquery/dist/jquery.min.js",
          "node_modules/signalr/jquery.signalR.min.js"
        ]
    ...

Create signalr.service.ts file:

import { Injectable } from '@angular/core';

declare var $: any;

@Injectable({
  providedIn: 'root'
})
export class SignalrService {

  private connection: any;
  private proxy: any;

  constructor() { }

  public initializeSignalRConnection(): void {
    this.connection = $.hubConnection(`${your_server_baseUrl}/signalr_map`, { useDefaultPath: false });
// Please note that by default '/signalr' URL will be used to connect to your SignalR service. Providing 'useDefaultPath' allows you to customize it
    this.proxy = this.connection.createHubProxy('connectionHub');

    this.proxy.on('messageReceived', (serverMessage) => this.onMessageReceived(serverMessage));

    this.connection.start().done((data: any) => {
      console.log('Connected to Connection Hub');
      this.sendMessage();
    }).catch((error: any) => {
      console.log('Connection Hub error:' + error);
    });
  }

  public sendMessage(): void {
    this.proxy.invoke('ClientMessage', 'My message')
      .catch((error: any) => {
        console.log('sending message error -> ' + error);
      });
  }

  private onMessageReceived(serverMessage: string) {
    console.log('New message received from Server: ' + serverMessage);
  }

}

don't forget to declare jquery symbol

declare var $: any;

and now you can use your signalr service in the component:

constructor(private signalRService: SignalrService) { 
  this.signalRService.initializeSignalRConnection()
}

hope this helps

Adriatic answered 7/2, 2023 at 16:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.