Angular ist ein sehr beliebtes Framework für Web-Frontends von Google. Da SignalR für ASP.NET Core bereits einen TypeScript-Client mitbringt, lässt es sich sehr einfach in Kombination verwenden. In diesem Artikel wird eine Angular App für das Chat-Backend des letzten Artikels entwickelt.

Vorbedingungen

Folgendes muss vorab installiert sein:

Dieser Artikel setzt auf das Beispiel aus dem letzten Artikel auf.

Angular Projekt erzeugen

Zunächst erzeugen wir ein neues Angular Projekt. Hierzu verwenden wir Angular CLI. Dieses wird in einem Konsolenfenster über folgenden Befehl installiert:

> npm install -g @angular/cli

Daraufhin können wir ein einfaches Angular Projekt erzeugen, indem wir im Projektverzeichnis den folgenden Befehl ausführen:

> ng new angular-chat

Der Vorgang kann etwas länger dauern, weil die nötigen JavaScript Pakete automatisch heruntergeladen und installiert werden. Wenn der Vorgang erfolgreich beendet wurde, öffnen wir die Datei app.module.ts und fügen das FormsModule hinzu (Zeilen 3 und 13):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Durch das FormsModule wird der App ermöglicht, eine Datenbindung auf Formularelementen zu verwenden (das benötigen wir später).

SignalR Clientbibliothek installieren

Jetzt installieren wir den SignalR-Client über den Node Paketmanager. Hierzu wird folgender Befehl im Projektverzeichnis in einer Konsole ausgeführt:

> npm install @aspnet/signalr-client --save

Angular Komponente hinzufügen

Nun können wir mit der eigentlichen Implementierung des Chat-Clients in Angular beginnen. Dazu erzeugen wir eine neue Komponente, indem wir folgenden Befehl in der Konsole, innerhalb des neu erzeugten Verzeichnisses angular-chat ausführen:

> ng g component chat

Angular CLI generiert daraufhin eine leere Komponente und ein HTML-Template. Der folgende Code wird in die neu erstellte Datei chat.component.ts eingefügt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { Component, OnInit } from '@angular/core';
import { HubConnection } from '@aspnet/signalr-client';

@Component({
  selector: 'app-chat',
  templateUrl: './chat.component.html',
  styleUrls: ['./chat.component.css']
})
export class ChatComponent implements OnInit {
  private hubConnection: HubConnection;
  message = '';
  messages = [];

  constructor() {
   }

  ngOnInit() {
    this.hubConnection = new HubConnection('/chat');

    this.hubConnection.on('broadcast', (message: string) => {
      this.messages.push(message);
    });

    this.hubConnection.start();
  }

  sendMessage(): void {
    this.hubConnection.invoke('send', this.message);
    this.message = '';
  }
}

Im Event ngOnInit wird zunächst eine HubConnection auf dem Endpunkt /chat erzeugt, den wir im Backend definiert haben. Daraufhin wird das Ereignis broadcast abonniert und ankommende Nachrichten werden in einer Liste messages abgelegt. Ebenfalls wird eine Verbindung zum Hub gestartet.

Über die Methode sendMessage kann eine Nachricht über die HubConnection gesendet werden.

HTML-Template

Jetzt benötigen wir noch das HTML-Template. Hierzu fügen wir den folgenden Code der Datei chat.component.html ein:

1
2
3
4
5
6
7
<div>
  <input type="text" id="message" />
  <input type="button" id="send" value="Senden" (click)="sendMessage()" />
  <ul id="messages">
    <li *ngFor="let message of messages"></li>
  </ul>
</div>

Die Schaltfläche zum Senden wird auf die Methode sendMessage gebunden und die angekommenen Nachrichten werden in einer Listendarstellung angezeigt.

Damit die Komponente verwendet werden kann, muss sie noch in ein anderes Template eingebunden werden (z.B. in die app.component.html):

1
<app-chat></app-chat>

App erstellen und starten

Zunächst konfigurieren wir das Ausgabeverzeichnis des Angular-Builds auf das wwwroot Verzeichnis. Hierzu öffnen wir die Datei .angular-cli.json und ändern den Eintrag outDir auf ”../wwwroot”.

Um die Anwendung zu erstellen, öffnen wir eine Konsole im Verzeichnis angular-chat und führen den Befehl: ng build aus.

Der Server kann über den Befehl dotnet run im Hauptverzeichnis gestartet werden.

Demo des Chats Demo des Chats

Tipp zum Debuggen

Zum Debuggen von Frontend und Backend in Kombination wird bei Angular Projekten häufig der Proxy von Webpacks Entwicklungsserver verwendet. Dieser lässt sich auch für SignalR verwenden, indem WebSocket-Verbindungen aktiviert werden.

1
2
3
4
5
6
[{
  "context": ["/chat"],
  "target": "http://localhost:5000",
  "secure": false,
  "ws": true
}]

Hier in dem Beispiel werden alle Anfragen an die Route /chat an Port 5000 weitergeleitet. Durch das Attribut ws: true werden auch WebSocket-Verbindungen über den Proxy aktiviert.

Tipp zu dotnet Performance

Nach der Installation von Angular kann man einen deutlichen Performanceeinbruch beim Erstellprozess des ASP.NET Backends feststellen. Das liegt an den NodeJS Paketen im node_modules Ordner. Dieser sollte eigentlich bereits automatisch aus dem Build ausgeschlossen sein - ich vermute das ist zurzeit noch ein Bug im Buildprozess der dotnet CLI.

Das Problem lässt sich recht einfach lösen, indem folgende Zeilen in die die .csproj-Datei hinzugefügt werden:

1
2
3
<PropertyGroup>
    <DefaultItemExcludes>node_modules/**;angular-client/**;.git/**;$(DefaultItemExcludes)</DefaultItemExcludes>
</PropertyGroup>

Dadurch werden alle Vorkommnisse des node_modules Ordners ignoriert und vom Build exkludiert. Auch werden alle Quelldateien des Angular-Clients exkludiert, die im fertig gebauten Projekt ebenfalls nicht benötigt werden.

Da ich häufig im Hauptverzeichnis ein Git-Projekt initialisiere, habe ich auch den Ordner .git hinzugefügt. Dieser führt ansonsten ebenfalls zu größeren Performanceeinbrüchen.

Beispielprojekt

Das Beispielprojekt ist hier auf GitHub zu finden.

Zusammenfassung

In diesem Artikel wurde das Chat-Beispiel aus dem letzten Artikel um ein Angular Frontend erweitert. Durch die bei SignalR mitgelieferten TypeScript Klassen integriert sich SignalR sehr gut in Angular Projekte. Auch das Debugging gestaltet sich über den Webpack Proxy als sehr einfach.

Weiterführende Links