
Teilen Sie:
Ehemaliger .NET Developer Advocate @Vonage, polyglotter Software-Ingenieur, AI/ML
Erstellen einer einfachen Video-Chat-Anwendung mit ASP.NET und Angular
Lesedauer: 11 Minuten
Angular ist bei weitem das beliebteste Single-Page Application (SPA) Framework, das von .NET-Entwicklern verwendet wird. Bis zu diesem Projekt hatte ich Angular nicht mehr verwendet, seit vor das JS aus dem Namen gestrichen wurde. Folglich war ich begeistert, es wieder einmal auszuprobieren, dieses Mal, um die Video API von Vonage vorzustellen. In diesem Tutorial erstellen wir eine einfache Video-Chat-Anwendung mit Angular (obwohl es immer das JS in meinem ❤ haben wird).
Voraussetzungen
Visual Studio (ich verwende 2019, aber ältere Versionen sollten auch funktionieren)
.NET Core 3.1 Entwickler-Kit
Ein Video API-Projekt von Vonage, das auf Ihrer Account-Seite erstellt werden kann
Direkt zum Code
Wenn Sie nur den Code für diesen Durchgang herunterladen möchten, besuchen Sie die GitHub Seite für diesen Blogbeitrag, befolgen Sie die Anweisungen, und schon sind Sie fertig.
Das Wichtigste zuerst
Beginnen wir mit dem Öffnen von Visual Studio. Klicken Sie auf . Ein neues Projekt erstellen -> ASP.NET Core-Webanwendung -> Geben Sie der Anwendung einen Namen (ich nenne mein Projekt BasicVideoChatAngular) -> erstellen -> Angular.
Auf diese Weise wird eine ASP.NET-Shell-Anwendung mit dem gesamten clientseitigen Code im Ordner ClientApp Ordner.
Nuget-Pakete importieren
Importieren Sie die folgenden NuGet-Pakete für dieses Projekt:
OpenTok
Microsoft.EntityFrameworkCore.SqlServer (ich verwende 3.1.3)
Erstellen des Entitätsmodells
Wir werden hier ein sehr einfaches Entity Framework verwenden. Fügen Sie eine Model.cs Datei zum Projekt hinzu. Löschen Sie die Klassendeklaration und fügen Sie den folgenden Code hinzu:
public class OpentokContext : DbContext
{
public DbSet<Room> Rooms { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=VonageVideo.db");
}
public class Room
{
public int RoomId { get; set; }
public string SessionId { get; set; }
public string RoomName { get; set; }
public string Token { get; set; }
}Außerdem müssen Sie dem Abschnitt using folgendes hinzufügen:
using Microsoft.EntityFrameworkCore; Erstellen Sie die Datenbank
Nun können wir die Datenbank erstellen. Navigieren Sie zu Ihrem Projektordner und führen Sie Folgendes aus:
Dadurch wird eine Datenbankdatei erstellt, die Ihre Räume und Sitzungsnummern enthält.
Einen Session Controller erstellen
Rechtsklick auf den Controllers Ordner -> Hinzufügen -> Steuerung - MVC-Steuerung - Leeren Sie -> benennen SessionController.
In der SessionControllerAbhängigkeit injizieren wir ein IConfiguration-Objekt und erstellen eine elementare Formularklasse, die unseren Raumnamen enthält. RoomForm:
private IConfiguration _Configuration;
public SessionController(IConfiguration config)
{
_Configuration = config;
}
public class RoomForm
{
public string RoomName { get; set; }
}Fügen Sie danach eine HttpPost-Anforderung namens GetSession die eine RoomForm als Argument annimmt:
[HttpPost]
public IActionResult GetSession([FromBody]RoomForm roomForm)
{
var apiKey = int.Parse(_Configuration["ApiKey"]);
var apiSecret = _Configuration["ApiSecret"];
var opentok = new OpenTok(apiKey, apiSecret);
var roomName = roomForm.RoomName;
string sessionId;
string token;
using (var db = new OpentokContext())
{
var room = db.Rooms.Where(r => r.RoomName == roomName).FirstOrDefault();
if (room != null)
{
sessionId = room.SessionId;
token = opentok.GenerateToken(sessionId);
room.Token = token;
db.SaveChanges();
}
else
{
var session = opentok.CreateSession();
sessionId = session.Id;
token = opentok.GenerateToken(sessionId);
var roomInsert = new Room
{
SessionId = sessionId,
Token = token,
RoomName = roomName
};
db.Add(roomInsert);
db.SaveChanges();
}
}
return Json(new { sessionId = sessionId, token = token, apiKey = _Configuration["ApiKey"] });
}
Diese Methode prüft die Datenbank, um festzustellen, ob der Raumname bereits eine SessionId hat. Wenn ja, wird ein Token für diese SessionId erzeugt. Wenn nicht, werden eine neue Sitzung und ein neues Token erstellt. Dann wird eine neue Zeile in der Datenbank für diesen Raum erstellt. In beiden Fällen werden eine SessionId, ein Token und ein ApiKey als JSON zurückgegeben.
Den Kunden aufbauen
Nachdem das Backend fertiggestellt ist, können wir uns nun an die Erstellung des Clients machen. Wir werden zwei Hauptansichten haben - unsere Beitreten Ansicht, in die der Benutzer den Namen des Raums eingibt, dem er beitreten möchte:
Chat App Join View
Und ein Video Ansicht, die den Videoanruf enthalten wird:
Chat App Video View
npm-Abhängigkeiten installieren
Als Erstes navigieren Sie zum Verzeichnis ClientApp Verzeichnis in Ihrem Terminal und führen Sie es aus:
Demo-Ansichten entrümpeln
Wenn Sie ein Angular-Projekt in Visual Studio erstellen, werden automatisch eine Reihe von Demo-Komponenten unter ClientApp\src\app, einschließlich counter, fetch-data, homeund nav-menu. Wir brauchen sie nicht, also löschen wir sie einfach von vornherein.
Benötigte Dateien hinzufügen
Erstellen Sie die folgenden Ordner/Dateien:
Unter
ClientApp\srchinzufügenconfig.tsUnter
ClientApp\src\apphinzufügenstateService.tsUnter
ClientApp\src\appVerzeichnisse erstellen:join,subscriber,videoUnter
ClientApp\src\joinerstellenjoin.component.css,join.component.html,join.component.tsUnter
ClientApp\src\subscribererstellensubscriber.component.html,subscriber.component.ts,subscriber.component.cssUnter
ClientApp\src\videoerstellenvideo.component.css,video.component.html,video.component.ts
Erstellen Sie die Konfiguration
In ClientApp\src\config.ts, werden wir unsere Konfiguration einrichten, die ein Feld enthält, SAMPLE_SERVER_BASE_URL. Setzen Sie dieses Feld auf die Basis-URL, die Sie für den IIS verwenden - die Datei sollte wie folgt aussehen:
export default {
SAMPLE_SERVER_BASE_URL: 'https://localhost:44340'
}Wenn Sie IIS Express zum Debuggen verwenden, finden Sie die base_url indem Sie mit der rechten Maustaste auf Ihre Projektdatei klicken -> Eigenschaften -> Debuggenund am unteren Rand sehen Sie die IIS-URLs.
Den StateService ausbauen
Nachdem wir auf die Schaltfläche Join geklickt haben, wird es einen Übergang zwischen den Komponenten geben. Wir müssen das Token, die SessionId und den ApiKey zwischen der Join-Komponente und der Video-Komponente übertragen, damit die Video-Komponente dem Aufruf beitreten kann. Um dieses Problem zu lösen, werden wir diesen Zustand mithilfe eines Zustandsdienstes gemeinsam nutzen - wir werden den Zustandsdienst in die nächste Komponente injizieren, wenn wir zwischen ihnen wechseln. Dazu brauchen wir nur ein Injectable mit einigen beobachtbaren Feldern:
import { Injectable } from "@angular/core";
@Injectable({providedIn:'root'})
export class StateService {
public token$: string;
public sessionId$: string;
public apiKey$: string;
constructor() {}
}Anmerkung: Zu diesem Zeitpunkt könnte ein IntelliSense-Fehler auftreten: "Experimental support for decorators is a feature that is subject to change in a future release. Setzen Sie die Option 'experimentalDecorators', um diese Warnung zu entfernen" Um dies zu beheben, müssen Sie die Build-Aktion von ClientApp\tsconfig.json Datei auf Inhalt setzen, und Sie müssen Visual Studio möglicherweise neu starten.
Erstellen Sie die Abonnenten-Komponente
Die Komponente Subscriber ist die Komponente, die für den eingehenden Videostream verantwortlich ist. Um diese Komponente zu erstellen, entfernen Sie das gesamte vorinstallierte HTML aus subscriber.component.html und fügen Sie diese Zeile hinzu:
<div class="subscriber-div" #subscriberDiv></div>
Er enthält nur ein div, das als Ziel für den eingehenden Stream dient.
Jetzt in subscriber.component.cssein paar Stile hinzufügen:
.subscriber-div {
height: 100%;
width: 100%;
position: fixed;
top:50px;
bottom: 0;
left: 0;
z-index: 0;
}
.container {
background: black;
color: white;
height: 100%;
}Dieses CSS sorgt dafür, dass die Komponente den gesamten Bildschirm einnimmt und an den unteren Rand des Z-Index verschoben wird, wodurch verhindert wird, dass sie das Video des Herausgebers überholt, das als PIP am unteren Rand erscheint.
In der subscriber.component.ts filewerden wir eine Komponente mit einer Sitzung und einem Stream-Input erstellen. Sie benötigt außerdem einen Elementverweis auf die SubscriberDiv aus der HTML-Vorlage sowie eine Sitzung und einen Stream, die wir von der Videokomponente erhalten werden. Schließlich benötigt sie eine subscribe-Methode, um einen Session-Stream zu abonnieren, wenn das onStreamCreate Ereignis ausgelöst wird. Fügen Sie den folgenden Code in die Datei ein:
import { Component, ElementRef, ViewChild, Input } from '@angular/core';
import * as OT from '@opentok/client';
@Component({
selector: 'app-subscriber',
templateUrl: './subscriber.component.html',
styleUrls: ['./subscriber.component.css']
})
export class SubscriberComponent {
@ViewChild('subscriberDiv', { static: true }) subscriberDiv: ElementRef;
@Input() session: OT.Session;
@Input() stream: OT.Stream;
constructor() { }
subscribe(): void {
const subscriber = this.session.subscribe(this.stream, this.subscriberDiv.nativeElement, {
insertMode: "append",
width: "100%",
height: "100%"
}, (err) => {
if (err) {
alert(err.message);
}
});
}
}
Erstellen Sie die Video-Komponente
Beginnen wir mit der video.component.html Datei. Löschen Sie zunächst alle automatisch erstellten HTML-Dateien, die dieser Datei hinzugefügt wurden. Fügen Sie dann die Vorlage hinzu:
<div class="publishingDiv" [ngClass]="{'publishing': publishing}" #publisherDiv></div>
<div>
<ng-template #subscriberHost></ng-template>
</div>
Die publishingDiv wird der Anker im DOM sein, den wir für den Video-Feed unseres Herausgebers verwenden werden. Die subscriberHost Vorlage wird der Bereich sein, in dem unser Abonnent hinzugefügt wird, wenn ein Abonnent einem Aufruf beitritt. In der CSS-Datei lassen wir alle automatisch generierten CSS weg. Fügen Sie Stile hinzu, die das publishingDiv in die linke untere Ecke des Bildschirms an einer festen Position platziert wird, 25 % der Höhe und Breite des Fensters einnimmt und einen Z-Index von 1 hat (direkt über der Stelle, an der wir unser subscriberDiv). Fügen Sie Folgendes in die video.component.css Datei hinzu:
.publishingDiv {
height: 25%;
width: 25%;
left: 0;
bottom: 0;
position: fixed;
z-index: 1;
}Schließlich müssen wir noch die Komponente selbst einrichten. Erinnern Sie sich an die StateService von vorhin? Wir werden sie injizieren; von ihr werden wir die SessionId, das Token und den ApiKey vom SessionController erhalten, den wir zuvor erstellt haben.
Einfuhren und Abrichten des Bauteils
Zuerst importieren wir alles, was wir brauchen, und erstellen die VideoComponent Klasse.
import { ViewContainerRef, Component, ElementRef, AfterViewInit, ViewChild, ComponentFactoryResolver, OnInit } from '@angular/core';
import * as OT from '@opentok/client';
import { SubscriberComponent } from '../subscriber/subscriber.component';
import { StateService } from '../stateService';
import { Router } from '@angular/router';
@Component({
selector: 'app-video',
templateUrl: './video.component.html',
styleUrls: ['./video.component.css']
})
export class VideoComponent implements AfterViewInit, OnInit {
} Komponentenfelder und Konstrukteure
Als nächstes richten Sie einige Felder für die VideoComponent Klasse und den Konstruktor ein. Im Konstruktor injizieren wir ein ComponentFactoryResolverein, das wir verwenden, um später die native Referenz des subscriberHosts zu erhalten, und das Feld StateService, aus dem wir unseren apiKey, Token und sessionId beziehen. Der Router hilft uns bei der Weiterleitung zwischen den Komponenten in unserem Projekt. Insbesondere benötigen wir ihn, um zurück zum Join-Controller zu navigieren, wenn der State Service keinen apiKey, kein Token und keine SessionId enthält.
Innerhalb der VideoComponent Klasse ist Folgendes hinzuzufügen:
@ViewChild('publisherDiv', { static: false }) publisherDiv: ElementRef;
@ViewChild('subscriberHost', { read: ViewContainerRef, static: true }) subscriberHost: ViewContainerRef;
session: OT.Session;
publisher: OT.Publisher;
publishing;
apiKey: string;
token: string;
sessionId: string;
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private stateService: StateService,
private router: Router
) { } Zur Initialen Logik
Als nächstes werden wir die ngOnInit Funktion ein. Die StateService wird sofort bei init injiziert, daher werden wir dort den apiKey, das Token und die sessionId abrufen. Diese Funktion wird diese Elemente speichern. Wenn eines dieser Elemente nicht vorhanden ist, werden wir auf die Join-Seite umleiten.
ngOnInit(): void {
if (!this.stateService.apiKey$ || !this.stateService.token$ || !this.stateService.sessionId$) {
this.router.navigate(['/']);
}
this.apiKey = this.stateService.apiKey$;
this.token = this.stateService.token$;
this.sessionId = this.stateService.sessionId$;
} Veröffentlichen Sie den Stream des Benutzers
Als nächstes werden wir die Veröffentlichungsmethode einrichten. Wir rufen sie auf, nachdem die Ansicht die Initialisierung abgeschlossen hat. Diese Funktion ruft die Veröffentlichungsmethode der Sitzung auf und übergibt das Herausgeberelement. Sie übergibt das Veröffentlichungsfeld an true wenn der Rückruf aufgelöst wird. Fügen Sie das folgende nach ngOnInit:
publish() {
this.session.publish(this.publisher, (err) => {
if (err) {
console.log(err)
}
else {
this.publishing = true;
}
});
}
Die Erstellung eines Streams handhaben
Nach der Erstellung des Streams müssen wir ihn abonnieren. Dies geschieht, indem wir den Verweis auf die Abonnentenvorlage, die wir im HTML-Code erstellt haben, übernehmen, eine Abonnentenkomponente initialisieren, ihr den Stream und die Sitzungsnummer zuweisen und sie zum Abonnieren auffordern. Fügen Sie Folgendes nach der Veröffentlichungsmethode hinzu:
onStreamCreated(stream) {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(SubscriberComponent);
const viewContainerRef = this.subscriberHost;
const componentRef = viewContainerRef.createComponent(componentFactory);
(<SubscriberComponent>componentRef.instance).stream = stream;
(<SubscriberComponent>componentRef.instance).session = this.session;
(<SubscriberComponent>componentRef.instance).subscribe();
} Einrichten des Herausgebers
Nachdem die Ansicht initialisiert wurde, ngAfterViewInit ausgelöst. An diesem Punkt im Lebenszyklus des Controllers haben wir alles, was wir brauchen, um den Videoaufruf zu starten. Wir werden den Verleger initialisieren, die Sitzung initialisieren, uns mit der Sitzung verbinden und im Callback, nachdem wir uns mit der Sitzung verbunden haben, unserem Stream sagen, dass er veröffentlichen soll. Wir werden auch das Ereignis streamCreated Ereignis, das die Funktion onStreamCreated Funktion aufruft, die wir zuvor erstellt haben. Fügen Sie Folgendes hinzu ngAfterViewInit Funktion:
ngAfterViewInit(): void {
this.publisher = OT.initPublisher
(
this.publisherDiv.nativeElement, {
height: "100%",
width: "100%",
insertMode: 'append'
});
this.session = OT.initSession(this.apiKey, this.sessionId);
this.session.connect(this.token, (err) => {
if (err) {
console.log(err);
}
else {
console.log("connected");
this.publish()
let that = this;
this.session.on("streamCreated", function (event) {
that.onStreamCreated(event.stream);
});
}
})
}
Erstellen Sie die Join-Komponente
Nachdem wir die Videokomponente erstellt haben, müssen wir nur noch die Join-Komponente und das App-Modul einrichten.
Einrichten der Html
In der join.component.html Datei werden wir eine joinFormerstellen, die nur eine Eingabe hat, eine roomNamedie wir verwenden werden, um die SessionId's und Token zu erfassen/erzeugen. Die Vorlage für die Komponente wird wie folgt aussehen:
<form class="joinForm" [formGroup]="joinRoomForm" (ngSubmit)="onSubmit(joinRoomForm.value)">
<div>
<input placeholder="room name" id="roomName" type="text" formControlName="roomName" align="center">
</div>
<button align="center" class="button" type="submit">Join</button>
</form>
Einige Stile hinzufügen
Wir werden hier nichts allzu Ausgefallenes mit den Stilen machen - wir werden nur sicherstellen, dass die Schaltfläche und die Eingabe zentriert sind und die gleiche Größe haben. Fügen Sie Folgendes hinzu join.component.css:
form {
display: normal;
text-align: center;
margin: auto;
}
input {
display: inline-block;
font-size: inherit;
padding: .5em;
margin-bottom: .2em;
width: 300px;
}
button {
display: inline-block;
font-size: inherit;
padding: .5em;
width: 300px;
} Erstellen Sie die Komponente
Die Beitrittskomponente wird eine Übermittlungsfunktion für das Beitrittsformular haben, die die Sitzungsdaten von unserem Backend abruft und die Sitzungsdaten über den Statusdienst an die Videokomponente weiterleitet. Zu diesem Zweck wird die Funktion HttpClient, FormBuilder, StateServiceund Router Dienste über Dependency Injection ein und erstellt dann das Raumformular. Als nächstes wartet es auf eine onSubmit von joinRoomFormwarten, woraufhin es die Antwort roomName an den Sitzungscontroller und verwendet diese Antwort, um die Komponente Video zu erstellen.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import config from '../../config';
import { StateService } from '../stateService';
@Component({
selector: 'app-join',
templateUrl: '/join.component.html',
styleUrls: ['/join.component.css']
})
export class JoinComponent {
joinRoomForm;
constructor(
private http: HttpClient,
private formBuilder: FormBuilder,
private stateService: StateService,
private router: Router) {
this.joinRoomForm = this.formBuilder.group({
roomName: ''
});
}
onSubmit(roomData) {
let get_session_url = config.SAMPLE_SERVER_BASE_URL + '/session/getSession'
this.http.post(get_session_url, roomData).subscribe(
(res) => {
this.stateService.token$ = res['token'];
this.stateService.sessionId$ = res['sessionId'];
this.stateService.apiKey$ = res['apiKey'];
this.router.navigate(['/video'])
}
)
}
}
Einrichten der App
Bevor wir mit Angular arbeiten können, müssen wir das gesamte App-Modul einrichten. Wir beginnen mit dem Einrichten des Basis-HTML. In ClientApp\src\app\app.component.htmlhabe ich einen Titel oberhalb von router-outlethinzugefügt, der garantiert, dass der Titel auf unseren Unterseiten angezeigt wird. Stellen Sie außerdem sicher, dass Sie das <app-nav-menu></app-nav-menu>entfernen, da dieses bereits in der ursprünglich erstellten Vorlage vorhanden ist:
<body>
<div class="container">
<b><p style="font-size: 34px; text-align:center">Basic Angular Video Chat</p></b>
<router-outlet></router-outlet>
</div>
</body>
Als nächstes müssen wir in ClientApp\src\app\app.module.tsmüssen wir unser Modul definieren, d. h. wir fügen die neuen Komponenten hinzu, die wir erstellt haben, entfernen die Komponenten, die wir ganz am Anfang entfernt haben, und legen die Routen fest, die wir verwenden wollen. Fügen Sie die Komponenten als Importe hinzu und vergewissern Sie sich, dass Sie im Deklarationsfeld die HttpClientModule, FormsModule, ReactiveFormsModule, und RouterModule in Ihrem Importabschnitt. SubscriberComponent wird eine Einstiegskomponente sein. Die Routen werden wie folgt aussehen: '' -> JoinComponent, video -> VideoComponent, subscriber -> SubscriberComponent.
Konfigurieren Sie Ihre App.
Sie müssen die Konfiguration an zwei Stellen einrichten, config.ts und appsettings.json. Sie sollten die Konfiguration config.ts schon früher eingerichtet haben, also werde ich das nicht noch einmal wiederholen. Für appsettings.tsfügen Sie einfach apiKey und apiSecret als Felder hinzu und füllen Sie sie mit dem ApiKey und ApiSecret aus Ihrem Vonage Video API Account. Die Datei wird in etwa so aussehen:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ApiKey": "",
"ApiSecret": ""
}Damit sollte alles fertig sein! Ich hatte ein paar Probleme mit der Angular-Versionierung, als ich die Demo-App zum ersten Mal gebaut habe - Sie können sich gerne meine package.json Datei von GitHub.
Prüfung
Zum Testen müssen Sie lediglich die Anwendung in IIS Express starten - klicken Sie auf die Schaltfläche Debug oder drücken Sie f5 in Visual Studio. Daraufhin wird die Seite Beitreten aufgerufen. Geben Sie einen Raumnamen ein, und Sie werden einer neuen Sitzung beitreten, die mit diesem Raum verbunden ist. Sie können einen anderen Endpunkt zu demselben Endpunkt navigieren und demselben Raum beitreten lassen, so dass dieser mit Ihnen dem Raum beitritt.
Einpacken
Nachdem Sie nun die Grundstruktur einer Video-Chat-Anwendung in Angular erstellt haben, können Sie mit den Video APIs von Vonage noch viel mehr machen. Sie können Sitzungen aufzeichnen, Ihre Medien teilen, Ihre Videoanrufe streamen und vieles mehr!