Esercitazione: Introduzione a ASP.NET Core SignalR con TypeScript e Webpack
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Questa esercitazione illustra l'uso di Webpack in un'app Web ASP.NET Core SignalR per aggregare e compilare un client scritto in TypeScript. Webpack consente agli sviluppatori di creare un bundle delle risorse di un'app Web sul lato client-e di compilarle.
In questa esercitazione apprenderai a:
- Creare un'app ASP.NET Core SignalR
- Configurare il SignalR server
- Configurare una pipeline di compilazione tramite Webpack
- Configurare il SignalR client TypeScript
- Abilitare la comunicazione tra il client e il server
Visualizzare o scaricare il codice di esempio (procedura per il download)
Prerequisiti
Visual Studio 2022 con il carico di lavoro Sviluppo ASP.NET e Web.
Creare l'app Web ASP.NET Core
Per impostazione predefinita, Visual Studio usa la versione di npm trovata nella directory di installazione. Per configurare Visual Studio per cercare npm nella PATH
variabile di ambiente:
Avviare Visual Studio. Nella finestra iniziale selezionare Continua senza codice.
Passare a Strumenti>Opzioni>Progetti e soluzioni>Gestione pacchetti Web>Strumenti Web esterni.
Selezionare la
$(PATH)
voce dall'elenco. Selezionare la freccia su per spostare la voce nella seconda posizione nell'elenco e selezionare OK:.
Per creare una nuova app Web ASP.NET Core:
- Usare l'opzione di menu File>nuovo>progetto e scegliere il modello ASP.NET core vuoto. Selezionare Avanti.
- Assegnare al progetto
SignalRWebpack
il nome e selezionare Crea. - Selezionare .NET 8.0 (supporto a lungo termine) dall'elenco a discesa Framework . Seleziona Crea.
Aggiungere il pacchetto NuGet Microsoft.TypeScript.MSBuild al progetto:
- In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet. Nella scheda Sfoglia cercare
Microsoft.TypeScript.MSBuild
e quindi selezionare Installa a destra per installare il pacchetto.
Visual Studio aggiunge il pacchetto NuGet nel nodo Dipendenze in Esplora soluzioni, abilitando la compilazione TypeScript nel progetto.
Configurare il server
In questa sezione viene configurata l'app Web ASP.NET Core per inviare e ricevere SignalR messaggi.
In
Program.cs
chiamare AddSignalR:var builder = WebApplication.CreateBuilder(args); builder.Services.AddSignalR();
Anche in
Program.cs
, chiamare UseDefaultFiles e UseStaticFiles:var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles();
Il codice precedente consente al server di individuare e gestire il
index.html
file. Il file viene gestito indipendentemente dal fatto che l'utente immetta l'URL completo o l'URL radice dell'app Web.Creare una nuova directory denominata
Hubs
nella radice del progetto,SignalRWebpack/
, per la SignalR classe hub.Creare un nuovo file,
Hubs/ChatHub.cs
, con il codice seguente:using Microsoft.AspNetCore.SignalR; namespace SignalRWebpack.Hubs; public class ChatHub : Hub { public async Task NewMessage(long username, string message) => await Clients.All.SendAsync("messageReceived", username, message); }
Il codice precedente trasmette i messaggi ricevuti a tutti gli utenti connessi dopo che il server li riceve. Non è necessario avere un metodo generico
on
per ricevere tutti i messaggi. Un metodo denominato dopo il nome del messaggio è sufficiente.In questo esempio:
- Il client TypeScript invia un messaggio identificato come
newMessage
. - Il metodo C#
NewMessage
si aspetta i dati inviati dal client. - Viene effettuata una chiamata a SendAsync su Clients.All.
- I messaggi ricevuti vengono inviati a tutti i client connessi all'hub.
- Il client TypeScript invia un messaggio identificato come
Aggiungere l'istruzione seguente
using
all'inizio diProgram.cs
per risolvere ilChatHub
riferimento:using SignalRWebpack.Hubs;
In
Program.cs
eseguire il mapping della/hub
route all'hubChatHub
. Sostituire il codice visualizzatoHello World!
con il codice seguente:app.MapHub<ChatHub>("/hub");
Configurare il client
In questa sezione viene creato un progetto Node.js per convertire TypeScript in JavaScript e aggregare le risorse lato client, incluso HTML e CSS, usando Webpack.
Eseguire il comando seguente nella radice del progetto per creare un
package.json
file:npm init -y
Aggiungere la proprietà evidenziata al
package.json
file e salvare le modifiche apportate al file:{ "name": "SignalRWebpack", "version": "1.0.0", "private": true, "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Impostando la proprietà
private
sutrue
si evita la visualizzazione di avvisi di installazione del pacchetto nel passaggio successivo.Installare i pacchetti npm necessari. Eseguire il comando seguente dalla radice del progetto:
npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli
L'opzione
-E
disabilita il comportamento predefinito di npm per la scrittura di operatori di intervallo di controllo delle versioni semantici inpackage.json
. Ad esempio, viene usato"webpack": "5.76.1"
invece di"webpack": "^5.76.1"
. Questa opzione impedisce che vengano eseguiti aggiornamenti non desiderati a versioni più recenti del pacchetto.Per altre informazioni, vedere la documentazione di npm-install .
Sostituire la
scripts
proprietà delpackage.json
file con il codice seguente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },
Vengono definiti gli script seguenti:
build
: raggruppa le risorse lato client in modalità di sviluppo e controlla le modifiche dei file. Questo controllo fa sì che il bundle venga rigenerato a ogni modifica del file di progetto. L'opzionemode
disabilita le ottimizzazioni di produzione, come l'eliminazione del codice non utilizzato e la minimizzazione. usobuild
solo in fase di sviluppo.release
: raggruppa le risorse lato client in modalità di produzione.publish
: esegue lo scriptrelease
per creare il bundle delle risorse sul lato client in modalità di produzione. Chiama il comando publish dell'interfaccia della riga di comando di .NET per pubblicare l'app.
Creare un file denominato
webpack.config.js
nella radice del progetto con il codice seguente:const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, "wwwroot"), filename: "[name].[chunkhash].js", publicPath: "/", }, resolve: { extensions: [".js", ".ts"], }, module: { rules: [ { test: /\.ts$/, use: "ts-loader", }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"], }, ], }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./src/index.html", }), new MiniCssExtractPlugin({ filename: "css/[name].[chunkhash].css", }), ], };
Il file precedente configura il processo di compilazione Webpack:
- La
output
proprietà esegue l'override del valore predefinito didist
. Il bundle viene invece generato nellawwwroot
directory . - La
resolve.extensions
matrice include.js
per importare il SignalR client JavaScript.
- La
Creare una nuova directory denominata
src
nella radice del progetto,SignalRWebpack/
, per il codice client.Copiare la
src
directory e il relativo contenuto dal progetto di esempio nella radice del progetto. Lasrc
directory contiene i file seguenti:index.html
, che definisce il markup boilerplate della home page:<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>ASP.NET Core SignalR with TypeScript and Webpack</title> </head> <body> <div id="divMessages" class="messages"></div> <div class="input-zone"> <label id="lblMessage" for="tbMessage">Message:</label> <input id="tbMessage" class="input-zone-input" type="text" /> <button id="btnSend">Send</button> </div> </body> </html>
css/main.css
, che fornisce stili CSS per la home page:*, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; padding: 0; } .input-zone { align-items: center; display: flex; flex-direction: row; margin: 10px; } .input-zone-input { flex: 1; margin-right: 10px; } .message-author { font-weight: bold; } .messages { border: 1px solid #000; margin: 10px; max-height: 300px; min-height: 300px; overflow-y: auto; padding: 5px; }
tsconfig.json
, che configura il compilatore TypeScript per produrre JavaScript compatibile con ECMAScript 5:{ "compilerOptions": { "target": "es5" } }
index.ts
:import * as signalR from "@microsoft/signalr"; import "./css/main.css"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { const m = document.createElement("div"); m.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(m); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch((err) => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.key === "Enter") { send(); } }); btnSend.addEventListener("click", send); function send() { connection.send("newMessage", username, tbMessage.value) .then(() => (tbMessage.value = "")); }
Il codice precedente recupera i riferimenti agli elementi DOM e associa due gestori eventi:
keyup
: viene attivato quando l'utente digita nellatbMessage
casella di testo e chiama lasend
funzione quando l'utente preme il tasto INVIO .click
: viene attivato quando l'utente seleziona il pulsante Invia e chiamasend
la funzione .
La classe
HubConnectionBuilder
crea un nuovo compilatore per la configurazione della connessione al server. La funzionewithUrl
configura l'URL dell'hub.SignalR consente lo scambio di messaggi tra un client e un server. Ogni messaggio ha un nome specifico. Ad esempio, i messaggi con il nome
messageReceived
possono eseguire la logica responsabile della visualizzazione del nuovo messaggio nell'area messaggi. L'ascolto di un messaggio specifico può essere eseguito tramite la funzioneon
. È possibile restare in ascolto di un numero qualsiasi di nomi di messaggi. Si può anche passare parametri al messaggio, come il nome dell'autore e il contenuto del messaggio ricevuto. Quando il client riceve un messaggio, viene creato un nuovo elementodiv
con il nome dell'autore e il contenuto del messaggio nell'attributoinnerHTML
. Viene aggiunto all'elementodiv
principale che visualizza i messaggi.Per inviare un messaggio attraverso la connessione WebSockets è necessario chiamare il metodo
send
. Il primo parametro del metodo è il nome del messaggio. I dati del messaggio sono rappresentati dagli altri parametri. In questo esempio un messaggio identificato comenewMessage
viene inviato al server. Il messaggio è costituito dal nome utente e dall'input dell'utente in una casella di testo. Se l'invio riesce, il valore della casella di testo viene cancellato.
Eseguire il comando seguente nella radice del progetto:
npm i @microsoft/signalr @types/node
Il comando precedente installa:
- Client SignalR TypeScript, che consente al client di inviare messaggi al server.
- Le definizioni dei tipi TypeScript per Node.js, che consentono il controllo in fase di compilazione dei tipi Node.js.
Testare l'app
Verificare che l'app funzioni con la procedura seguente:
Eseguire Webpack in
release
modalità . Usando la finestra della console di Gestione pacchetti, eseguire il comando seguente nella radice del progetto.npm run release
Questo comando genera gli asset sul lato client da gestire durante l'esecuzione dell'app. Gli asset vengono inseriti nella
wwwroot
cartella .Webpack ha completato le attività seguenti:
- Ripulito il contenuto della
wwwroot
directory. - Convertito TypeScript in JavaScript in un processo noto come transpilazione.
- Mangled javaScript generato per ridurre le dimensioni dei file in un processo noto come minification.
- Copiati i file JavaScript, CSS e HTML elaborati da
src
allawwwroot
directory. - Inserire gli elementi seguenti nel
wwwroot/index.html
file:- Tag
<link>
che fa riferimento alwwwroot/main.<hash>.css
file. Questo tag viene inserito immediatamente prima del tag</head>
di chiusura. - Tag
<script>
che fa riferimento al file minimizzatowwwroot/main.<hash>.js
. Questo tag viene inserito immediatamente dopo il tag di chiusura</title>
.
- Tag
- Ripulito il contenuto della
Selezionare Debug>Avvia senza eseguire il debug per avviare l'app in un browser senza collegare il debugger. Il
wwwroot/index.html
file viene gestito inhttps://localhost:<port>
.Se sono presenti errori di compilazione, provare a chiudere e riaprire la soluzione.
Aprire un'altra istanza di un browser qualsiasi e incollare l'URL nella barra dell'indirizzo.
Scegliere uno dei browser, digitare qualcosa nella casella di testo Messaggio e selezionare il pulsante Invia . Il nome utente e il messaggio univoci vengono visualizzati immediatamente in entrambe le pagine.
Passaggi successivi
- Hub fortemente tipizzato
- Autenticazione e autorizzazione in ASP.NET Core SignalR
- Protocollo hub MessagePack in SignalR per ASP.NET Core
Risorse aggiuntive
Questa esercitazione illustra l'uso di Webpack in un'app Web ASP.NET Core SignalR per aggregare e compilare un client scritto in TypeScript. Webpack consente agli sviluppatori di creare un bundle delle risorse di un'app Web sul lato client-e di compilarle.
In questa esercitazione apprenderai a:
- Creare un'app ASP.NET Core SignalR
- Configurare il SignalR server
- Configurare una pipeline di compilazione tramite Webpack
- Configurare il SignalR client TypeScript
- Abilitare la comunicazione tra il client e il server
Visualizzare o scaricare il codice di esempio (procedura per il download)
Prerequisiti
Visual Studio 2022 con il carico di lavoro Sviluppo ASP.NET e Web.
Creare l'app Web ASP.NET Core
Per impostazione predefinita, Visual Studio usa la versione di npm trovata nella directory di installazione. Per configurare Visual Studio per cercare npm nella PATH
variabile di ambiente:
Avviare Visual Studio. Nella finestra iniziale selezionare Continua senza codice.
Passare a Strumenti>Opzioni>Progetti e soluzioni>Gestione pacchetti Web>Strumenti Web esterni.
Selezionare la
$(PATH)
voce dall'elenco. Selezionare la freccia su per spostare la voce nella seconda posizione nell'elenco e selezionare OK:.
Per creare una nuova app Web ASP.NET Core:
- Usare l'opzione di menu File>nuovo>progetto e scegliere il modello ASP.NET core vuoto. Selezionare Avanti.
- Assegnare al progetto
SignalRWebpack
il nome e selezionare Crea. - Selezionare
.NET 7.0 (Standard Term Support)
dall'elenco a discesa Framework . Seleziona Crea.
Aggiungere il pacchetto NuGet Microsoft.TypeScript.MSBuild al progetto:
- In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet. Nella scheda Sfoglia cercare
Microsoft.TypeScript.MSBuild
e quindi selezionare Installa a destra per installare il pacchetto.
Visual Studio aggiunge il pacchetto NuGet nel nodo Dipendenze in Esplora soluzioni, abilitando la compilazione TypeScript nel progetto.
Configurare il server
In questa sezione viene configurata l'app Web ASP.NET Core per inviare e ricevere SignalR messaggi.
In
Program.cs
chiamare AddSignalR:var builder = WebApplication.CreateBuilder(args); builder.Services.AddSignalR();
Anche in
Program.cs
, chiamare UseDefaultFiles e UseStaticFiles:var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles();
Il codice precedente consente al server di individuare e gestire il
index.html
file. Il file viene gestito indipendentemente dal fatto che l'utente immetta l'URL completo o l'URL radice dell'app Web.Creare una nuova directory denominata
Hubs
nella radice del progetto,SignalRWebpack/
, per la SignalR classe hub.Creare un nuovo file,
Hubs/ChatHub.cs
, con il codice seguente:using Microsoft.AspNetCore.SignalR; namespace SignalRWebpack.Hubs; public class ChatHub : Hub { public async Task NewMessage(long username, string message) => await Clients.All.SendAsync("messageReceived", username, message); }
Il codice precedente trasmette i messaggi ricevuti a tutti gli utenti connessi dopo che il server li riceve. Non è necessario avere un metodo generico
on
per ricevere tutti i messaggi. Un metodo denominato dopo il nome del messaggio è sufficiente.In questo esempio:
- Il client TypeScript invia un messaggio identificato come
newMessage
. - Il metodo C#
NewMessage
si aspetta i dati inviati dal client. - Viene effettuata una chiamata a SendAsync su Clients.All.
- I messaggi ricevuti vengono inviati a tutti i client connessi all'hub.
- Il client TypeScript invia un messaggio identificato come
Aggiungere l'istruzione seguente
using
all'inizio diProgram.cs
per risolvere ilChatHub
riferimento:using SignalRWebpack.Hubs;
In
Program.cs
eseguire il mapping della/hub
route all'hubChatHub
. Sostituire il codice visualizzatoHello World!
con il codice seguente:app.MapHub<ChatHub>("/hub");
Configurare il client
In questa sezione viene creato un progetto Node.js per convertire TypeScript in JavaScript e aggregare le risorse lato client, incluso HTML e CSS, usando Webpack.
Eseguire il comando seguente nella radice del progetto per creare un
package.json
file:npm init -y
Aggiungere la proprietà evidenziata al
package.json
file e salvare le modifiche apportate al file:{ "name": "SignalRWebpack", "version": "1.0.0", "private": true, "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Impostando la proprietà
private
sutrue
si evita la visualizzazione di avvisi di installazione del pacchetto nel passaggio successivo.Installare i pacchetti npm necessari. Eseguire il comando seguente dalla radice del progetto:
npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli
L'opzione
-E
disabilita il comportamento predefinito di npm per la scrittura di operatori di intervallo di controllo delle versioni semantici inpackage.json
. Ad esempio, viene usato"webpack": "5.76.1"
invece di"webpack": "^5.76.1"
. Questa opzione impedisce che vengano eseguiti aggiornamenti non desiderati a versioni più recenti del pacchetto.Per altre informazioni, vedere la documentazione di npm-install .
Sostituire la
scripts
proprietà delpackage.json
file con il codice seguente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },
Vengono definiti gli script seguenti:
build
: raggruppa le risorse lato client in modalità di sviluppo e controlla le modifiche dei file. Questo controllo fa sì che il bundle venga rigenerato a ogni modifica del file di progetto. L'opzionemode
disabilita le ottimizzazioni di produzione, come l'eliminazione del codice non utilizzato e la minimizzazione. usobuild
solo in fase di sviluppo.release
: raggruppa le risorse lato client in modalità di produzione.publish
: esegue lo scriptrelease
per creare il bundle delle risorse sul lato client in modalità di produzione. Chiama il comando publish dell'interfaccia della riga di comando di .NET per pubblicare l'app.
Creare un file denominato
webpack.config.js
nella radice del progetto con il codice seguente:const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, "wwwroot"), filename: "[name].[chunkhash].js", publicPath: "/", }, resolve: { extensions: [".js", ".ts"], }, module: { rules: [ { test: /\.ts$/, use: "ts-loader", }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"], }, ], }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./src/index.html", }), new MiniCssExtractPlugin({ filename: "css/[name].[chunkhash].css", }), ], };
Il file precedente configura il processo di compilazione Webpack:
- La
output
proprietà esegue l'override del valore predefinito didist
. Il bundle viene invece generato nellawwwroot
directory . - La
resolve.extensions
matrice include.js
per importare il SignalR client JavaScript.
- La
Copiare la
src
directory e il relativo contenuto dal progetto di esempio nella radice del progetto. Lasrc
directory contiene i file seguenti:index.html
, che definisce il markup boilerplate della home page:<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>ASP.NET Core SignalR with TypeScript and Webpack</title> </head> <body> <div id="divMessages" class="messages"></div> <div class="input-zone"> <label id="lblMessage" for="tbMessage">Message:</label> <input id="tbMessage" class="input-zone-input" type="text" /> <button id="btnSend">Send</button> </div> </body> </html>
css/main.css
, che fornisce stili CSS per la home page:*, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; padding: 0; } .input-zone { align-items: center; display: flex; flex-direction: row; margin: 10px; } .input-zone-input { flex: 1; margin-right: 10px; } .message-author { font-weight: bold; } .messages { border: 1px solid #000; margin: 10px; max-height: 300px; min-height: 300px; overflow-y: auto; padding: 5px; }
tsconfig.json
, che configura il compilatore TypeScript per produrre JavaScript compatibile con ECMAScript 5:{ "compilerOptions": { "target": "es5" } }
index.ts
:import * as signalR from "@microsoft/signalr"; import "./css/main.css"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { const m = document.createElement("div"); m.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(m); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch((err) => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.key === "Enter") { send(); } }); btnSend.addEventListener("click", send); function send() { connection.send("newMessage", username, tbMessage.value) .then(() => (tbMessage.value = "")); }
Il codice precedente recupera i riferimenti agli elementi DOM e associa due gestori eventi:
keyup
: viene attivato quando l'utente digita nellatbMessage
casella di testo e chiama lasend
funzione quando l'utente preme il tasto INVIO .click
: viene attivato quando l'utente seleziona il pulsante Invia e chiamasend
la funzione .
La classe
HubConnectionBuilder
crea un nuovo compilatore per la configurazione della connessione al server. La funzionewithUrl
configura l'URL dell'hub.SignalR consente lo scambio di messaggi tra un client e un server. Ogni messaggio ha un nome specifico. Ad esempio, i messaggi con il nome
messageReceived
possono eseguire la logica responsabile della visualizzazione del nuovo messaggio nell'area messaggi. L'ascolto di un messaggio specifico può essere eseguito tramite la funzioneon
. È possibile restare in ascolto di un numero qualsiasi di nomi di messaggi. Si può anche passare parametri al messaggio, come il nome dell'autore e il contenuto del messaggio ricevuto. Quando il client riceve un messaggio, viene creato un nuovo elementodiv
con il nome dell'autore e il contenuto del messaggio nell'attributoinnerHTML
. Viene aggiunto all'elementodiv
principale che visualizza i messaggi.Per inviare un messaggio attraverso la connessione WebSockets è necessario chiamare il metodo
send
. Il primo parametro del metodo è il nome del messaggio. I dati del messaggio sono rappresentati dagli altri parametri. In questo esempio un messaggio identificato comenewMessage
viene inviato al server. Il messaggio è costituito dal nome utente e dall'input dell'utente in una casella di testo. Se l'invio riesce, il valore della casella di testo viene cancellato.
Eseguire il comando seguente nella radice del progetto:
npm i @microsoft/signalr @types/node
Il comando precedente installa:
- Client SignalR TypeScript, che consente al client di inviare messaggi al server.
- Le definizioni dei tipi TypeScript per Node.js, che consentono il controllo in fase di compilazione dei tipi Node.js.
Testare l'app
Verificare che l'app funzioni con la procedura seguente:
Eseguire Webpack in
release
modalità . Usando la finestra della console di Gestione pacchetti, eseguire il comando seguente nella radice del progetto.npm run release
Questo comando genera gli asset sul lato client da gestire durante l'esecuzione dell'app. Gli asset vengono inseriti nella
wwwroot
cartella .Webpack ha completato le attività seguenti:
- Ripulito il contenuto della
wwwroot
directory. - Convertito TypeScript in JavaScript in un processo noto come transpilazione.
- Mangled javaScript generato per ridurre le dimensioni dei file in un processo noto come minification.
- Copiati i file JavaScript, CSS e HTML elaborati da
src
allawwwroot
directory. - Inserire gli elementi seguenti nel
wwwroot/index.html
file:- Tag
<link>
che fa riferimento alwwwroot/main.<hash>.css
file. Questo tag viene inserito immediatamente prima del tag</head>
di chiusura. - Tag
<script>
che fa riferimento al file minimizzatowwwroot/main.<hash>.js
. Questo tag viene inserito immediatamente dopo il tag di chiusura</title>
.
- Tag
- Ripulito il contenuto della
Selezionare Debug>Avvia senza eseguire il debug per avviare l'app in un browser senza collegare il debugger. Il
wwwroot/index.html
file viene gestito inhttps://localhost:<port>
.Se sono presenti errori di compilazione, provare a chiudere e riaprire la soluzione.
Aprire un'altra istanza di un browser qualsiasi e incollare l'URL nella barra dell'indirizzo.
Scegliere uno dei browser, digitare qualcosa nella casella di testo Messaggio e selezionare il pulsante Invia . Il nome utente e il messaggio univoci vengono visualizzati immediatamente in entrambe le pagine.
Passaggi successivi
- Hub fortemente tipizzato
- Autenticazione e autorizzazione in ASP.NET Core SignalR
- Protocollo hub MessagePack in SignalR per ASP.NET Core
Risorse aggiuntive
Questa esercitazione illustra l'uso di Webpack in un'app Web ASP.NET Core SignalR per aggregare e compilare un client scritto in TypeScript. Webpack consente agli sviluppatori di creare un bundle delle risorse di un'app Web sul lato client-e di compilarle.
In questa esercitazione apprenderai a:
- Creare un'app ASP.NET Core SignalR
- Configurare il SignalR server
- Configurare una pipeline di compilazione tramite Webpack
- Configurare il SignalR client TypeScript
- Abilitare la comunicazione tra il client e il server
Visualizzare o scaricare il codice di esempio (procedura per il download)
Prerequisiti
- Visual Studio 2022 con il carico di lavoro Sviluppo ASP.NET e Web.
- .NET 6.0 SDK
Creare l'app Web ASP.NET Core
Per impostazione predefinita, Visual Studio usa la versione di npm trovata nella directory di installazione. Per configurare Visual Studio per cercare npm nella PATH
variabile di ambiente:
Avviare Visual Studio. Nella finestra iniziale selezionare Continua senza codice.
Passare a Strumenti>Opzioni>Progetti e soluzioni>Gestione pacchetti Web>Strumenti Web esterni.
Selezionare la
$(PATH)
voce dall'elenco. Selezionare la freccia su per spostare la voce nella seconda posizione nell'elenco e selezionare OK:.
Per creare una nuova app Web ASP.NET Core:
- Usare l'opzione di menu File>nuovo>progetto e scegliere il modello ASP.NET core vuoto. Selezionare Avanti.
- Assegnare al progetto
SignalRWebpack
il nome e selezionare Crea. - Selezionare
.NET 6.0 (Long Term Support)
dall'elenco a discesa Framework . Seleziona Crea.
Aggiungere il pacchetto NuGet Microsoft.TypeScript.MSBuild al progetto:
- In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet. Nella scheda Sfoglia cercare
Microsoft.TypeScript.MSBuild
e quindi selezionare Installa a destra per installare il pacchetto.
Visual Studio aggiunge il pacchetto NuGet nel nodo Dipendenze in Esplora soluzioni, abilitando la compilazione TypeScript nel progetto.
Configurare il server
In questa sezione viene configurata l'app Web ASP.NET Core per inviare e ricevere SignalR messaggi.
In
Program.cs
chiamare AddSignalR:var builder = WebApplication.CreateBuilder(args); builder.Services.AddSignalR();
Anche in
Program.cs
, chiamare UseDefaultFiles e UseStaticFiles:var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles();
Il codice precedente consente al server di individuare e gestire il
index.html
file. Il file viene gestito indipendentemente dal fatto che l'utente immetta l'URL completo o l'URL radice dell'app Web.Creare una nuova directory denominata
Hubs
nella radice del progetto,SignalRWebpack/
, per la SignalR classe hub.Creare un nuovo file,
Hubs/ChatHub.cs
, con il codice seguente:using Microsoft.AspNetCore.SignalR; namespace SignalRWebpack.Hubs; public class ChatHub : Hub { public async Task NewMessage(long username, string message) => await Clients.All.SendAsync("messageReceived", username, message); }
Il codice precedente trasmette i messaggi ricevuti a tutti gli utenti connessi dopo che il server li riceve. Non è necessario avere un metodo generico
on
per ricevere tutti i messaggi. Un metodo denominato dopo il nome del messaggio è sufficiente.In questo esempio il client TypeScript invia un messaggio identificato come
newMessage
. Il metodo C#NewMessage
si aspetta i dati inviati dal client. Viene effettuata una chiamata a SendAsync su Clients.All. I messaggi ricevuti vengono inviati a tutti i client connessi all'hub.Aggiungere l'istruzione seguente
using
all'inizio diProgram.cs
per risolvere ilChatHub
riferimento:using SignalRWebpack.Hubs;
In
Program.cs
eseguire il mapping della/hub
route all'hubChatHub
. Sostituire il codice visualizzatoHello World!
con il codice seguente:app.MapHub<ChatHub>("/hub");
Configurare il client
In questa sezione viene creato un progetto Node.js per convertire TypeScript in JavaScript e aggregare le risorse lato client, incluso HTML e CSS, usando Webpack.
Eseguire il comando seguente nella radice del progetto per creare un
package.json
file:npm init -y
Aggiungere la proprietà evidenziata al
package.json
file e salvare le modifiche apportate al file:{ "name": "SignalRWebpack", "version": "1.0.0", "private": true, "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Impostando la proprietà
private
sutrue
si evita la visualizzazione di avvisi di installazione del pacchetto nel passaggio successivo.Installare i pacchetti npm necessari. Eseguire il comando seguente dalla radice del progetto:
npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli
L'opzione
-E
disabilita il comportamento predefinito di npm per la scrittura di operatori di intervallo di controllo delle versioni semantici inpackage.json
. Ad esempio, viene usato"webpack": "5.70.0"
invece di"webpack": "^5.70.0"
. Questa opzione impedisce che vengano eseguiti aggiornamenti non desiderati a versioni più recenti del pacchetto.Per altre informazioni, vedere la documentazione di npm-install .
Sostituire la
scripts
proprietà delpackage.json
file con il codice seguente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },
Vengono definiti gli script seguenti:
build
: raggruppa le risorse lato client in modalità di sviluppo e controlla le modifiche dei file. Questo controllo fa sì che il bundle venga rigenerato a ogni modifica del file di progetto. L'opzionemode
disabilita le ottimizzazioni di produzione, come l'eliminazione del codice non utilizzato e la minimizzazione. usobuild
solo in fase di sviluppo.release
: raggruppa le risorse lato client in modalità di produzione.publish
: esegue lo scriptrelease
per creare il bundle delle risorse sul lato client in modalità di produzione. Chiama il comando publish dell'interfaccia della riga di comando di .NET per pubblicare l'app.
Creare un file denominato
webpack.config.js
nella radice del progetto con il codice seguente:const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, "wwwroot"), filename: "[name].[chunkhash].js", publicPath: "/", }, resolve: { extensions: [".js", ".ts"], }, module: { rules: [ { test: /\.ts$/, use: "ts-loader", }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"], }, ], }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./src/index.html", }), new MiniCssExtractPlugin({ filename: "css/[name].[chunkhash].css", }), ], };
Il file precedente configura il processo di compilazione Webpack:
- La
output
proprietà esegue l'override del valore predefinito didist
. Il bundle viene invece generato nellawwwroot
directory . - La
resolve.extensions
matrice include.js
per importare il SignalR client JavaScript.
- La
Copiare la
src
directory e il relativo contenuto dal progetto di esempio nella radice del progetto. Lasrc
directory contiene i file seguenti:index.html
, che definisce il markup boilerplate della home page:<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>ASP.NET Core SignalR with TypeScript and Webpack</title> </head> <body> <div id="divMessages" class="messages"></div> <div class="input-zone"> <label id="lblMessage" for="tbMessage">Message:</label> <input id="tbMessage" class="input-zone-input" type="text" /> <button id="btnSend">Send</button> </div> </body> </html>
css/main.css
, che fornisce stili CSS per la home page:*, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; padding: 0; } .input-zone { align-items: center; display: flex; flex-direction: row; margin: 10px; } .input-zone-input { flex: 1; margin-right: 10px; } .message-author { font-weight: bold; } .messages { border: 1px solid #000; margin: 10px; max-height: 300px; min-height: 300px; overflow-y: auto; padding: 5px; }
tsconfig.json
, che configura il compilatore TypeScript per produrre JavaScript compatibile con ECMAScript 5:{ "compilerOptions": { "target": "es5" } }
index.ts
:import * as signalR from "@microsoft/signalr"; import "./css/main.css"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { const m = document.createElement("div"); m.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(m); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch((err) => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.key === "Enter") { send(); } }); btnSend.addEventListener("click", send); function send() { connection.send("newMessage", username, tbMessage.value) .then(() => (tbMessage.value = "")); }
Il codice precedente recupera i riferimenti agli elementi DOM e associa due gestori eventi:
keyup
: viene attivato quando l'utente digita nellatbMessage
casella di testo e chiama lasend
funzione quando l'utente preme il tasto INVIO .click
: viene attivato quando l'utente seleziona il pulsante Invia e chiamasend
la funzione .
La classe
HubConnectionBuilder
crea un nuovo compilatore per la configurazione della connessione al server. La funzionewithUrl
configura l'URL dell'hub.SignalR consente lo scambio di messaggi tra un client e un server. Ogni messaggio ha un nome specifico. Ad esempio, i messaggi con il nome
messageReceived
possono eseguire la logica responsabile della visualizzazione del nuovo messaggio nell'area messaggi. L'ascolto di un messaggio specifico può essere eseguito tramite la funzioneon
. È possibile restare in ascolto di un numero qualsiasi di nomi di messaggi. Si può anche passare parametri al messaggio, come il nome dell'autore e il contenuto del messaggio ricevuto. Quando il client riceve un messaggio, viene creato un nuovo elementodiv
con il nome dell'autore e il contenuto del messaggio nell'attributoinnerHTML
. Viene aggiunto all'elementodiv
principale che visualizza i messaggi.Per inviare un messaggio attraverso la connessione WebSockets è necessario chiamare il metodo
send
. Il primo parametro del metodo è il nome del messaggio. I dati del messaggio sono rappresentati dagli altri parametri. In questo esempio un messaggio identificato comenewMessage
viene inviato al server. Il messaggio è costituito dal nome utente e dall'input dell'utente in una casella di testo. Se l'invio riesce, il valore della casella di testo viene cancellato.Eseguire il comando seguente nella radice del progetto:
npm i @microsoft/signalr @types/node
Il comando precedente installa:
- Client SignalR TypeScript, che consente al client di inviare messaggi al server.
- Le definizioni dei tipi TypeScript per Node.js, che consentono il controllo in fase di compilazione dei tipi Node.js.
Testare l'app
Verificare che l'app funzioni con la procedura seguente:
Eseguire Webpack in
release
modalità . Usando la finestra della console di Gestione pacchetti, eseguire il comando seguente nella radice del progetto. Se non si è nella radice del progetto, immetterecd SignalRWebpack
prima di immettere il comando .npm run release
Questo comando genera gli asset sul lato client da gestire durante l'esecuzione dell'app. Gli asset vengono inseriti nella
wwwroot
cartella .Webpack ha completato le attività seguenti:
- Ripulito il contenuto della
wwwroot
directory. - Convertito TypeScript in JavaScript in un processo noto come transpilazione.
- Mangled javaScript generato per ridurre le dimensioni dei file in un processo noto come minification.
- Copiati i file JavaScript, CSS e HTML elaborati da
src
allawwwroot
directory. - Inserire gli elementi seguenti nel
wwwroot/index.html
file:- Tag
<link>
che fa riferimento alwwwroot/main.<hash>.css
file. Questo tag viene inserito immediatamente prima del tag</head>
di chiusura. - Tag
<script>
che fa riferimento al file minimizzatowwwroot/main.<hash>.js
. Questo tag viene inserito immediatamente dopo il tag di chiusura</title>
.
- Tag
- Ripulito il contenuto della
Selezionare Debug>Avvia senza eseguire il debug per avviare l'app in un browser senza collegare il debugger. Il
wwwroot/index.html
file viene gestito inhttps://localhost:<port>
.Se vengono visualizzati errori di compilazione, provare a chiudere e riaprire la soluzione.
Aprire un'altra istanza di un browser qualsiasi e incollare l'URL nella barra dell'indirizzo.
Scegliere uno dei browser, digitare qualcosa nella casella di testo Messaggio e selezionare il pulsante Invia . Il nome utente e il messaggio univoci vengono visualizzati immediatamente in entrambe le pagine.
Passaggi successivi
- Hub fortemente tipizzato
- Autenticazione e autorizzazione in ASP.NET Core SignalR
- Protocollo hub MessagePack in SignalR per ASP.NET Core
Risorse aggiuntive
Questa esercitazione illustra l'uso di Webpack in un'app Web ASP.NET Core SignalR per aggregare e compilare un client scritto in TypeScript. Webpack consente agli sviluppatori di creare un bundle delle risorse di un'app Web sul lato client-e di compilarle.
In questa esercitazione apprenderai a:
- Eseguire lo scaffolding di un'app starter ASP.NET Core SignalR
- Configurare il SignalR client TypeScript
- Configurare una pipeline di compilazione tramite Webpack
- Configurare il SignalR server
- Abilitare la comunicazione tra client e server
Visualizzare o scaricare il codice di esempio (procedura per il download)
Prerequisiti
- Visual Studio 2019 con il carico di lavoro Sviluppo ASP.NET e Web
- .NET Core SDK 3.0 o versione successiva
- Node.js con npm
Creare l'app Web ASP.NET Core
Configurare Visual Studio in modo che cerchi npm nella variabile di ambiente PATH. Per impostazione predefinita, Visual Studio usa la versione di npm trovata nella directory di installazione. Seguire queste istruzioni in Visual Studio:
Avviare Visual Studio. Nella finestra iniziale selezionare Continua senza codice.
Passare a Strumenti>Opzioni>Progetti e soluzioni>Gestione pacchetti Web>Strumenti Web esterni.
Selezionare la voce $(PATH) dall'elenco. Selezionare la freccia su per spostare la voce nella seconda posizione nell'elenco e selezionare OK.
.
La configurazione di Visual Studio è stata completata.
- Selezionare l'opzione di menu File>Nuovo>Progetto e scegliere il modello Applicazione Web ASP.NET Core. Selezionare Avanti.
- Assegnare al progetto il nome *SignalRWebPac'' e selezionare Crea.
- Selezionare .NET Core dall'elenco a discesa framework di destinazione e selezionare ASP.NET Core 3.1 nell'elenco a discesa del selettore del framework. Selezionare il modello Vuoto e selezionare Crea.
Aggiungere il Microsoft.TypeScript.MSBuild
pacchetto al progetto:
- In Esplora soluzioni (riquadro destro) fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet. Nella scheda Sfoglia cercare
Microsoft.TypeScript.MSBuild
e quindi fare clic su Installa a destra per installare il pacchetto.
Visual Studio aggiunge il pacchetto NuGet nel nodo Dipendenze in Esplora soluzioni, abilitando la compilazione TypeScript nel progetto.
Configurare Webpack e TypeScript
I passaggi seguenti consentono di configurare la conversione da TypeScript a JavaScript e di creare un bundle delle risorse sul lato client.
Eseguire il comando seguente nella radice del progetto per creare un
package.json
file:npm init -y
Aggiungere la proprietà evidenziata al
package.json
file e salvare le modifiche apportate al file:{ "name": "SignalRWebPack", "version": "1.0.0", "private": true, "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Impostando la proprietà
private
sutrue
si evita la visualizzazione di avvisi di installazione del pacchetto nel passaggio successivo.Installare i pacchetti npm necessari. Eseguire il comando seguente dalla radice del progetto:
npm i -D -E clean-webpack-plugin@3.0.0 css-loader@3.4.2 html-webpack-plugin@3.2.0 mini-css-extract-plugin@0.9.0 ts-loader@6.2.1 typescript@3.7.5 webpack@4.41.5 webpack-cli@3.3.10
Ecco alcuni dettagli del comando da tenere in considerazione:
- Un numero di versione segue il segno
@
per ogni nome di pacchetto. npm installa queste versioni del pacchetto specifiche. - L'opzione
-E
disabilita il comportamento predefinito di npm per la scrittura di operatori di intervallo di controllo delle versioni semantici in *packagejson
. Ad esempio, viene usato"webpack": "4.41.5"
invece di"webpack": "^4.41.5"
. Questa opzione impedisce che vengano eseguiti aggiornamenti non desiderati a versioni più recenti del pacchetto.
Per altre informazioni, vedere la documentazione npm-install .
- Un numero di versione segue il segno
Sostituire la
scripts
proprietà delpackage.json
file con il codice seguente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },
Ecco una spiegazione degli script:
build
: raggruppa le risorse lato client in modalità di sviluppo e controlla le modifiche dei file. Questo controllo fa sì che il bundle venga rigenerato a ogni modifica del file di progetto. L'opzionemode
disabilita le ottimizzazioni di produzione, come l'eliminazione del codice non utilizzato e la minimizzazione. Usarebuild
solo in modalità di sviluppo.release
: raggruppa le risorse lato client in modalità di produzione.publish
: esegue lo scriptrelease
per creare il bundle delle risorse sul lato client in modalità di produzione. Chiama il comando publish dell'interfaccia della riga di comando di .NET Core per pubblicare l'app.
Creare un file denominato
webpack.config.js
, nella radice del progetto, con il codice seguente:const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, "wwwroot"), filename: "[name].[chunkhash].js", publicPath: "/" }, resolve: { extensions: [".js", ".ts"] }, module: { rules: [ { test: /\.ts$/, use: "ts-loader" }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] } ] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./src/index.html" }), new MiniCssExtractPlugin({ filename: "css/[name].[chunkhash].css" }) ] };
Il file precedente configura la compilazione di Webpack. Ecco alcuni dettagli di configurazione del server da tenere in considerazione:
- La
output
proprietà esegue l'override del valore predefinito didist
. Il bundle viene invece generato nellawwwroot
directory . - La
resolve.extensions
matrice include.js
per importare il SignalR client JavaScript.
- La
Creare una nuova directory src nella radice del progetto per archiviare gli asset lato client del progetto.
Creare
src/index.html
con il markup seguente.<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>ASP.NET Core SignalR</title> </head> <body> <div id="divMessages" class="messages"> </div> <div class="input-zone"> <label id="lblMessage" for="tbMessage">Message:</label> <input id="tbMessage" class="input-zone-input" type="text" /> <button id="btnSend">Send</button> </div> </body> </html>
Il codice HTML precedente definisce il markup del boilerplate della home page.
Creare una nuova directory src/css. Lo scopo è archiviare i file del
.css
progetto.Creare
src/css/main.css
con il codice CSS seguente:*, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; padding: 0; } .input-zone { align-items: center; display: flex; flex-direction: row; margin: 10px; } .input-zone-input { flex: 1; margin-right: 10px; } .message-author { font-weight: bold; } .messages { border: 1px solid #000; margin: 10px; max-height: 300px; min-height: 300px; overflow-y: auto; padding: 5px; }
Il file precedente
main.css
stili l'app.Creare
src/tsconfig.json
con il codice ON seguente JS:{ "compilerOptions": { "target": "es5" } }
Il codice precedente configura il compilatore TypeScript in modo da produrre codice JavaScript compatibile con ECMAScript 5.
Creare
src/index.ts
con il codice seguente:import "./css/main.css"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.key === "Enter") { send(); } }); btnSend.addEventListener("click", send); function send() { }
Il compilatore TypeScript precedente recupera i riferimenti agli elementi DOM e collega due gestori eventi:
keyup
: questo evento viene generato quando l'utente digita nellatbMessage
casella di testo. La funzionesend
viene chiamata quando l'utente preme INVIO.click
: questo evento viene generato quando l'utente seleziona il pulsante Invia . Viene chiamata la funzionesend
.
Configurare l'app
In
Startup.Configure
aggiungere chiamate a UseDefaultFiles(IApplicationBuilder) e UseStaticFiles(IApplicationBuilder).public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseDefaultFiles(); app.UseStaticFiles(); app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/hub"); }); }
Il codice precedente consente al server di individuare e gestire il
index.html
file. Il file viene gestito indipendentemente dal fatto che l'utente immetta l'URL completo o l'URL radice dell'app Web.Alla fine di eseguire il mapping di
Startup.Configure
una route /hub all'hubChatHub
. Sostituire il codice che visualizza Hello World! con la riga seguente:app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/hub"); });
In
Startup.ConfigureServices
chiamare AddSignalR.services.AddSignalR();
Creare una nuova directory denominata Hubs nella radiceSignalR del progetto WebPack/ per archiviare l'hubSignalR.
Creare l'hub
Hubs/ChatHub.cs
con il codice seguente:using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRWebPack.Hubs { public class ChatHub : Hub { } }
Aggiungere l'istruzione seguente
using
all'inizio delStartup.cs
file per risolvere ilChatHub
riferimento:using SignalRWebPack.Hubs;
Abilitare la comunicazione tra client e server
L'app visualizza attualmente un modulo di base per l'invio di messaggi, ma non è ancora funzionante. Il server è in ascolto di una route specifica, ma non esegue alcuna operazione con i messaggi inviati.
Eseguire il comando seguente nella radice del progetto:
npm i @microsoft/signalr @types/node
Il comando precedente installa:
- Client SignalR TypeScript, che consente al client di inviare messaggi al server.
- Le definizioni dei tipi TypeScript per Node.js, che consentono il controllo in fase di compilazione dei tipi Node.js.
Aggiungere il codice evidenziato al
src/index.ts
file:import "./css/main.css"; import * as signalR from "@microsoft/signalr"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { let m = document.createElement("div"); m.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(m); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch(err => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.key === "Enter") { send(); } }); btnSend.addEventListener("click", send); function send() { }
Il codice precedente supporta la ricezione di messaggi dal server. La classe
HubConnectionBuilder
crea un nuovo compilatore per la configurazione della connessione al server. La funzionewithUrl
configura l'URL dell'hub.SignalR consente lo scambio di messaggi tra un client e un server. Ogni messaggio ha un nome specifico. Ad esempio, i messaggi con il nome
messageReceived
possono eseguire la logica responsabile della visualizzazione del nuovo messaggio nell'area messaggi. L'ascolto di un messaggio specifico può essere eseguito tramite la funzioneon
. È possibile restare in ascolto di un numero qualsiasi di nomi di messaggi. Si può anche passare parametri al messaggio, come il nome dell'autore e il contenuto del messaggio ricevuto. Quando il client riceve un messaggio, viene creato un nuovo elementodiv
con il nome dell'autore e il contenuto del messaggio nell'attributoinnerHTML
. Viene aggiunto all'elementodiv
principale che visualizza i messaggi.Ora che il client può ricevere messaggi, configurarlo anche per l'invio. Aggiungere il codice evidenziato al
src/index.ts
file:import "./css/main.css"; import * as signalR from "@microsoft/signalr"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { let messages = document.createElement("div"); messages.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(messages); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch(err => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.key === "Enter") { send(); } }); btnSend.addEventListener("click", send); function send() { connection.send("newMessage", username, tbMessage.value) .then(() => tbMessage.value = ""); }
Per inviare un messaggio attraverso la connessione WebSockets è necessario chiamare il metodo
send
. Il primo parametro del metodo è il nome del messaggio. I dati del messaggio sono rappresentati dagli altri parametri. In questo esempio un messaggio identificato comenewMessage
viene inviato al server. Il messaggio è costituito dal nome utente e dall'input dell'utente in una casella di testo. Se l'invio riesce, il valore della casella di testo viene cancellato.Aggiungere il metodo
NewMessage
alla classeChatHub
:using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRWebPack.Hubs { public class ChatHub : Hub { public async Task NewMessage(long username, string message) { await Clients.All.SendAsync("messageReceived", username, message); } } }
Il codice precedente trasmette i messaggi ricevuti a tutti gli utenti connessi dopo che il server li riceve. Non è necessario avere un metodo generico
on
per ricevere tutti i messaggi. È sufficiente un metodo denominato dopo il nome del messaggio.In questo esempio il client TypeScript invia un messaggio identificato come
newMessage
. Il metodo C#NewMessage
si aspetta i dati inviati dal client. Viene effettuata una chiamata a SendAsync su Clients.All. I messaggi ricevuti vengono inviati a tutti i client connessi all'hub.
Testare l'app
Per verificare che l'app funzioni, eseguire la procedura seguente.
Eseguire Webpack in modalità versione. Usando la finestra della console di Gestione pacchetti, eseguire il comando seguente nella radice del progetto. Se non si è nella radice del progetto, immettere
cd SignalRWebPack
prima di immettere il comando .npm run release
Questo comando genera gli asset sul lato client da gestire durante l'esecuzione dell'app. Gli asset vengono inseriti nella
wwwroot
cartella .Webpack ha completato le attività seguenti:
- Ripulito il contenuto della
wwwroot
directory. - Convertito TypeScript in JavaScript in un processo noto come transpilazione.
- Mangled javaScript generato per ridurre le dimensioni dei file in un processo noto come minification.
- Copiati i file JavaScript, CSS e HTML elaborati da
src
allawwwroot
directory. - Inserire gli elementi seguenti nel
wwwroot/index.html
file:- Tag
<link>
che fa riferimento alwwwroot/main.<hash>.css
file. Questo tag viene inserito immediatamente prima del tag</head>
di chiusura. - Tag
<script>
che fa riferimento al file minimizzatowwwroot/main.<hash>.js
. Questo tag viene inserito immediatamente dopo il tag di chiusura</title>
.
- Tag
- Ripulito il contenuto della
Selezionare Debug>Avvia senza eseguire il debug per avviare l'app in un browser senza collegare il debugger. Il
wwwroot/index.html
file viene gestito inhttp://localhost:<port_number>
.Se vengono visualizzati errori di compilazione, provare a chiudere e riaprire la soluzione.
Aprire un'altra istanza del browser (qualsiasi browser). Incollare l'URL nella barra degli indirizzi.
Scegliere uno dei browser, digitare qualcosa nella casella di testo Messaggio e selezionare il pulsante Invia . Il nome utente e il messaggio univoci vengono visualizzati immediatamente in entrambe le pagine.
Risorse aggiuntive
Questa esercitazione illustra l'uso di Webpack in un'app Web ASP.NET Core SignalR per aggregare e compilare un client scritto in TypeScript. Webpack consente agli sviluppatori di creare un bundle delle risorse di un'app Web sul lato client-e di compilarle.
In questa esercitazione apprenderai a:
- Eseguire lo scaffolding di un'app starter ASP.NET Core SignalR
- Configurare il SignalR client TypeScript
- Configurare una pipeline di compilazione tramite Webpack
- Configurare il SignalR server
- Abilitare la comunicazione tra client e server
Visualizzare o scaricare il codice di esempio (procedura per il download)
Prerequisiti
- Visual Studio 2019 con il carico di lavoro Sviluppo ASP.NET e Web
- .NET Core SDK 2.2 o versione successiva
- Node.js con npm
Creare l'app Web ASP.NET Core
Configurare Visual Studio in modo che cerchi npm nella variabile di ambiente PATH. Per impostazione predefinita, Visual Studio usa la versione di npm trovata nella directory di installazione. Seguire queste istruzioni in Visual Studio:
Passare a Strumenti>Opzioni>Progetti e soluzioni>Gestione pacchetti Web>Strumenti Web esterni.
Selezionare la voce $(PATH) dall'elenco. Selezionare la freccia su per spostare la voce nella seconda posizione nell'elenco.
La configurazione di Visual Studio è completata. A questo punto è possibile creare il progetto
- Selezionare l'opzione di menu File>Nuovo>Progetto e scegliere il modello Applicazione Web ASP.NET Core.
- Assegnare al progetto il nome *SignalRWebPack' e selezionare Crea.
- Selezionare .NET Core nell'elenco a discesa del framework di destinazione e quindi selezionare ASP.NET Core 2.2 nell'elenco a discesa del selettore del framework. Selezionare il modello Vuoto e selezionare Crea.
Configurare Webpack e TypeScript
I passaggi seguenti consentono di configurare la conversione da TypeScript a JavaScript e di creare un bundle delle risorse sul lato client.
Eseguire il comando seguente nella radice del progetto per creare un
package.json
file:npm init -y
Aggiungere la proprietà evidenziata al
package.json
file:{ "name": "SignalRWebPack", "version": "1.0.0", "private": true, "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Impostando la proprietà
private
sutrue
si evita la visualizzazione di avvisi di installazione del pacchetto nel passaggio successivo.Installare i pacchetti npm necessari. Eseguire il comando seguente dalla radice del progetto:
npm install -D -E clean-webpack-plugin@1.0.1 css-loader@2.1.0 html-webpack-plugin@4.0.0-beta.5 mini-css-extract-plugin@0.5.0 ts-loader@5.3.3 typescript@3.3.3 webpack@4.29.3 webpack-cli@3.2.3
Ecco alcuni dettagli del comando da tenere in considerazione:
- Un numero di versione segue il segno
@
per ogni nome di pacchetto. npm installa queste versioni del pacchetto specifiche. - L'opzione
-E
disabilita il comportamento predefinito di npm per la scrittura di operatori di intervallo di controllo delle versioni semantici in *packagejson
. Ad esempio, viene usato"webpack": "4.29.3"
invece di"webpack": "^4.29.3"
. Questa opzione impedisce che vengano eseguiti aggiornamenti non desiderati a versioni più recenti del pacchetto.
Per altre informazioni, vedere la documentazione npm-install .
- Un numero di versione segue il segno
Sostituire la
scripts
proprietà delpackage.json
file con il codice seguente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },
Ecco una spiegazione degli script:
build
: raggruppa le risorse lato client in modalità di sviluppo e controlla le modifiche dei file. Questo controllo fa sì che il bundle venga rigenerato a ogni modifica del file di progetto. L'opzionemode
disabilita le ottimizzazioni di produzione, come l'eliminazione del codice non utilizzato e la minimizzazione. Usarebuild
solo in modalità di sviluppo.release
: raggruppa le risorse lato client in modalità di produzione.publish
: esegue lo scriptrelease
per creare il bundle delle risorse sul lato client in modalità di produzione. Chiama il comando publish dell'interfaccia della riga di comando di .NET Core per pubblicare l'app.
Creare un file denominato
*webpack.config.js
nella radice del progetto con il codice seguente:const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, "wwwroot"), filename: "[name].[chunkhash].js", publicPath: "/" }, resolve: { extensions: [".js", ".ts"] }, module: { rules: [ { test: /\.ts$/, use: "ts-loader" }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] } ] }, plugins: [ new CleanWebpackPlugin(["wwwroot/*"]), new HtmlWebpackPlugin({ template: "./src/index.html" }), new MiniCssExtractPlugin({ filename: "css/[name].[chunkhash].css" }) ] };
Il file precedente configura la compilazione di Webpack. Ecco alcuni dettagli di configurazione del server da tenere in considerazione:
- La
output
proprietà esegue l'override del valore predefinito didist
. Il bundle viene invece generato nellawwwroot
directory . - La
resolve.extensions
matrice include.js
per importare il SignalR client JavaScript.
- La
Creare una nuova directory src nella radice del progetto per archiviare gli asset lato client del progetto.
Creare
src/index.html
con il markup seguente.<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>ASP.NET Core SignalR</title> </head> <body> <div id="divMessages" class="messages"> </div> <div class="input-zone"> <label id="lblMessage" for="tbMessage">Message:</label> <input id="tbMessage" class="input-zone-input" type="text" /> <button id="btnSend">Send</button> </div> </body> </html>
Il codice HTML precedente definisce il markup del boilerplate della home page.
Creare una nuova directory src/css. Lo scopo è archiviare i file del
.css
progetto.Creare
src/css/main.css
con il markup seguente:*, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; padding: 0; } .input-zone { align-items: center; display: flex; flex-direction: row; margin: 10px; } .input-zone-input { flex: 1; margin-right: 10px; } .message-author { font-weight: bold; } .messages { border: 1px solid #000; margin: 10px; max-height: 300px; min-height: 300px; overflow-y: auto; padding: 5px; }
Il file precedente
main.css
stili l'app.Creare
src/tsconfig.json
con il codice ON seguente JS:{ "compilerOptions": { "target": "es5" } }
Il codice precedente configura il compilatore TypeScript in modo da produrre codice JavaScript compatibile con ECMAScript 5.
Creare
src/index.ts
con il codice seguente:import "./css/main.css"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.keyCode === 13) { send(); } }); btnSend.addEventListener("click", send); function send() { }
Il compilatore TypeScript precedente recupera i riferimenti agli elementi DOM e collega due gestori eventi:
keyup
: questo evento viene generato quando l'utente digita nellatbMessage
casella di testo. La funzionesend
viene chiamata quando l'utente preme INVIO.click
: questo evento viene generato quando l'utente seleziona il pulsante Invia . Viene chiamata la funzionesend
.
Configurare l'app ASP.NET Core
Il codice fornito nel metodo
Startup.Configure
visualizza Hello World!. Sostituire la chiamata alapp.Run
metodo con chiamate a UseDefaultFiles(IApplicationBuilder) e UseStaticFiles(IApplicationBuilder).app.UseDefaultFiles(); app.UseStaticFiles();
Il codice precedente consente al server di individuare e gestire il
index.html
file, indipendentemente dal fatto che l'utente immetta l'URL completo o l'URL radice dell'app Web.Chiamare AddSignalR in
Startup.ConfigureServices
. Aggiunge i SignalR servizi al progetto.services.AddSignalR();
Eseguire il mapping di una route /hub all'hub
ChatHub
. Aggiungere le righe seguenti alla fine diStartup.Configure
:app.UseSignalR(options => { options.MapHub<ChatHub>("/hub"); });
Creare una nuova directory denominata Hubs nella radice del progetto. Lo scopo è archiviare l'hub SignalR , creato nel passaggio successivo.
Creare l'hub
Hubs/ChatHub.cs
con il codice seguente:using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRWebPack.Hubs { public class ChatHub : Hub { } }
Aggiungere il codice seguente all'inizio del
Startup.cs
file per risolvere ilChatHub
riferimento:using SignalRWebPack.Hubs;
Abilitare la comunicazione tra client e server
L'app attualmente visualizza un semplice form per l'invio di messaggi. Quando si prova a eseguire questa operazione, non accade nulla. Il server è in ascolto di una route specifica, ma non esegue alcuna operazione con i messaggi inviati.
Eseguire il comando seguente nella radice del progetto:
npm install @aspnet/signalr
Il comando precedente installa il SignalR client TypeScript, che consente al client di inviare messaggi al server.
Aggiungere il codice evidenziato al
src/index.ts
file:import "./css/main.css"; import * as signalR from "@aspnet/signalr"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { let m = document.createElement("div"); m.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(m); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch(err => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.keyCode === 13) { send(); } }); btnSend.addEventListener("click", send); function send() { }
Il codice precedente supporta la ricezione di messaggi dal server. La classe
HubConnectionBuilder
crea un nuovo compilatore per la configurazione della connessione al server. La funzionewithUrl
configura l'URL dell'hub.SignalR consente lo scambio di messaggi tra un client e un server. Ogni messaggio ha un nome specifico. Ad esempio, i messaggi con il nome
messageReceived
possono eseguire la logica responsabile della visualizzazione del nuovo messaggio nell'area messaggi. L'ascolto di un messaggio specifico può essere eseguito tramite la funzioneon
. È possibile restare in ascolto di un numero indefinito di nomi di messaggio. Si può anche passare parametri al messaggio, come il nome dell'autore e il contenuto del messaggio ricevuto. Quando il client riceve un messaggio, viene creato un nuovo elementodiv
con il nome dell'autore e il contenuto del messaggio nell'attributoinnerHTML
. Il nuovo messaggio viene aggiunto all'elemento principalediv
che visualizza i messaggi.Ora che il client può ricevere messaggi, configurarlo anche per l'invio. Aggiungere il codice evidenziato al
src/index.ts
file:import "./css/main.css"; import * as signalR from "@aspnet/signalr"; const divMessages: HTMLDivElement = document.querySelector("#divMessages"); const tbMessage: HTMLInputElement = document.querySelector("#tbMessage"); const btnSend: HTMLButtonElement = document.querySelector("#btnSend"); const username = new Date().getTime(); const connection = new signalR.HubConnectionBuilder() .withUrl("/hub") .build(); connection.on("messageReceived", (username: string, message: string) => { let messageContainer = document.createElement("div"); messageContainer.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`; divMessages.appendChild(messageContainer); divMessages.scrollTop = divMessages.scrollHeight; }); connection.start().catch(err => document.write(err)); tbMessage.addEventListener("keyup", (e: KeyboardEvent) => { if (e.keyCode === 13) { send(); } }); btnSend.addEventListener("click", send); function send() { connection.send("newMessage", username, tbMessage.value) .then(() => tbMessage.value = ""); }
Per inviare un messaggio attraverso la connessione WebSockets è necessario chiamare il metodo
send
. Il primo parametro del metodo è il nome del messaggio. I dati del messaggio sono rappresentati dagli altri parametri. In questo esempio un messaggio identificato comenewMessage
viene inviato al server. Il messaggio è costituito dal nome utente e dall'input dell'utente in una casella di testo. Se l'invio riesce, il valore della casella di testo viene cancellato.Aggiungere il metodo
NewMessage
alla classeChatHub
:using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRWebPack.Hubs { public class ChatHub : Hub { public async Task NewMessage(long username, string message) { await Clients.All.SendAsync("messageReceived", username, message); } } }
Il codice precedente trasmette i messaggi ricevuti a tutti gli utenti connessi dopo che il server li riceve. Non è necessario avere un metodo generico
on
per ricevere tutti i messaggi. È sufficiente un metodo denominato dopo il nome del messaggio.In questo esempio il client TypeScript invia un messaggio identificato come
newMessage
. Il metodo C#NewMessage
si aspetta i dati inviati dal client. Viene effettuata una chiamata a SendAsync su Clients.All. I messaggi ricevuti vengono inviati a tutti i client connessi all'hub.
Testare l'app
Per verificare che l'app funzioni, eseguire la procedura seguente.
Eseguire Webpack in modalità versione. Usando la finestra della console di Gestione pacchetti, eseguire il comando seguente nella radice del progetto. Se non si è nella radice del progetto, immettere
cd SignalRWebPack
prima di immettere il comando .npm run release
Questo comando genera gli asset sul lato client da gestire durante l'esecuzione dell'app. Gli asset vengono inseriti nella
wwwroot
cartella .Webpack ha completato le attività seguenti:
- Ripulito il contenuto della
wwwroot
directory. - Convertito TypeScript in JavaScript in un processo noto come transpilazione.
- Mangled javaScript generato per ridurre le dimensioni dei file in un processo noto come minification.
- Copiati i file JavaScript, CSS e HTML elaborati da
src
allawwwroot
directory. - Inserire gli elementi seguenti nel
wwwroot/index.html
file:- Tag
<link>
che fa riferimento alwwwroot/main.<hash>.css
file. Questo tag viene inserito immediatamente prima del tag</head>
di chiusura. - Tag
<script>
che fa riferimento al file minimizzatowwwroot/main.<hash>.js
. Questo tag viene inserito immediatamente dopo il tag di chiusura</title>
.
- Tag
- Ripulito il contenuto della
Selezionare Debug>Avvia senza eseguire il debug per avviare l'app in un browser senza collegare il debugger. Il
wwwroot/index.html
file viene gestito inhttp://localhost:<port_number>
.Aprire un'altra istanza del browser (qualsiasi browser). Incollare l'URL nella barra degli indirizzi.
Scegliere uno dei browser, digitare qualcosa nella casella di testo Messaggio e selezionare il pulsante Invia . Il nome utente e il messaggio univoci vengono visualizzati immediatamente in entrambe le pagine.
Risorse aggiuntive
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per