Uso de ASP.NET Core SignalR con TypeScript and Webpack
Por Sébastien Sougnez y Scott Addie
Webpack permite a los desarrolladores agrupar y compilar los recursos del lado cliente de una aplicación web. En este tutorial se describe el uso de Webpack en una aplicación web ASP.NET Core SignalR cuyo cliente está escrito en TypeScript.
En este tutorial aprenderá a:
- Agregar scaffold a una aplicación ASP.NET Core SignalR de inicio
- Configurar el cliente de TypeScript para SignalR
- Configuración de una canalización de compilación mediante Webpack
- Configurar el servidor SignalR
- Habilitar la comunicación entre cliente y servidor
Vea o descargue el código de ejemplo (cómo descargarlo)
Requisitos previos
- Visual Studio 2019 con la carga de trabajo ASP.NET y desarrollo web
- .NET Core SDK 3.0 o posterior
- Node.js con npm
Creación de la aplicación web ASP.NET Core
Configure Visual Studio para buscar npm en la variable de entorno PATH. De forma predeterminada, Visual Studio usa la versión de npm que se encuentra en su directorio de instalación. Siga estas instrucciones en Visual Studio:
Inicie Visual Studio. En la ventana de inicio, seleccione Continuar sin código.
Vaya a Herramientas > Opciones > Proyectos y soluciones > Administración de paquetes web > Herramientas web externas.
Seleccione la entrada $(PATH) en la lista. Haga clic en la flecha arriba para mover la entrada a la segunda posición de la lista y seleccione Aceptar.

Se ha completado la configuración de Visual Studio.
- Use la opción de menú Archivo > Nuevo > Proyecto y seleccione la plantilla Aplicación web ASP.NET Core. Seleccione Siguiente.
- Asigne el nombre SignalRWebPack al proyecto y seleccione Crear.
- Seleccione .NET Core en la lista desplegable de plataformas de destino y ASP.NET Core 3.1 en la lista desplegable del selector de plataformas. Seleccione la plantilla Vacía y Crear.
Agregue el paquete Microsoft.TypeScript.MSBuild al proyecto:
- En el Explorador de soluciones (panel derecho), haga clic con el botón derecho en el nodo del proyecto y seleccione Administrar paquetes NuGet. En la pestaña Examinar, busque
Microsoft.TypeScript.MSBuildy luego haga clic en Instalar a la derecha para instalar el paquete.
Visual Studio agrega el paquete NuGet en el nodo Dependencias del Explorador de soluciones, que habilita la compilación de TypeScript en el proyecto.
Configuración de Webpack y TypeScript
Los pasos siguientes permiten configurar la conversión de TypeScript a JavaScript y la agrupación de los recursos del lado cliente.
Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:
npm init -yAgregue la propiedad resaltada al archivo package.json y guarde los cambios efectuados en el archivo:
{ "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" }Si establece la propiedad
privateentrue, evitará las advertencias de la instalación de paquetes en el paso siguiente.Instale los paquetes npm necesarios. Ejecute el comando siguiente desde la raíz del proyecto:
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.10Algunos detalles del comando para tener en cuenta:
- En cada nombre de paquete, un número de versión sigue al signo
@. npm instala esas versiones de paquete específicas. - La opción
-Edeshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de versionamiento semántico en package.json. Por ejemplo, se usa"webpack": "4.41.5"en lugar de"webpack": "^4.41.5". Esta opción impide actualizaciones no deseadas a versiones más recientes del paquete.
Consulte la documentación de npm-install para obtener más detalles.
- En cada nombre de paquete, un número de versión sigue al signo
Reemplace la propiedad
scriptsdel archivo package.json por el código siguiente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },Más detalles sobre los scripts:
build: agrupa los recursos del lado cliente en modo de desarrollo y supervisa los cambios del archivo. El monitor de archivos hace que la agrupación se vuelva a generar cada vez que cambia un archivo del proyecto. La opciónmodedeshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Usebuildúnicamente durante el desarrollo.release: agrupa los recursos del lado cliente en modo de producción.publish: ejecuta el scriptreleasepara agrupar los recursos del lado cliente en modo de producción. Llama al comando publish de la CLI de .NET Core para publicar la aplicación.
Cree un archivo denominado webpack.config.js, en la raíz del proyecto, con el código siguiente:
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" }) ] };El archivo anterior configura la compilación de Webpack. Algunos detalles de configuración para tener en cuenta:
- La propiedad
outputinvalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot. - La matriz
resolve.extensionsincluye .js para importar el código JavaScript del cliente de SignalR.
- La propiedad
Cree un src directorio en la raíz del proyecto para almacenar los recursos del lado cliente del proyecto.
Cree src/index.html con el marcado siguiente.
<!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>El código HTML anterior define el marcado reutilizable de la página principal.
Cree un directorio src/css. Su objetivo es almacenar los archivos .css del proyecto.
Cree src/css/main.css con la especificación CSS siguiente:
*, *::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; }El archivo main.css anterior aplica estilo a la aplicación.
Cree src/tsconfig.json con el JSON siguiente:
{ "compilerOptions": { "target": "es5" } }El código anterior configura el compilador de TypeScript para generar JavaScript compatible con ECMAScript 5.
Cree src/index.ts con el código siguiente:
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() { }El elemento TypeScript anterior recupera las referencias a elementos DOM y adjunta dos controladores de eventos:
keyup: este evento se desencadena cuando el usuario escribe algo en el cuadro de textotbMessage. La funciónsendse llama cuando el usuario presiona la tecla Entrar.click: este evento se desencadena cuando el usuario hace clic en el botón Enviar. Se llama a la funciónsend.
Configuración de la aplicación
En
Startup.Configure, agregue llamadas a UseDefaultFiles y UseStaticFiles.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"); }); }El código anterior permite que el servidor busque y entregue el archivo index.html. El archivo se entrega si el usuario escribe su dirección URL completa o la dirección URL raíz de la aplicación web.
Al final de
Startup.Configure, asigne una ruta /hub al centroChatHub. Reemplace el código que muestra Hola mundo por la línea siguiente:app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/hub"); });En
Startup.ConfigureServices, llame a AddSignalR.services.AddSignalR();Cree un directorio denominado Hubs en la raíz del proyecto SignalRWebPack/ para almacenar el centro SignalR.
Cree el concentrador Hubs/ChatHub.cs con el código siguiente:
using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRWebPack.Hubs { public class ChatHub : Hub { } }Agregue la instrucción
usingsiguiente en la parte superior del archivo Startup.cs para resolver la referencia aChatHub:using SignalRWebPack.Hubs;
Habilitar la comunicación entre cliente y servidor
La aplicación actualmente muestra un formulario básico para enviar mensajes, pero aún no es funcional. El servidor está escuchando en una ruta específica, pero no hace nada con los mensajes enviados.
Ejecute el comando siguiente en la raíz del proyecto:
npm i @microsoft/signalr @types/nodeEl comando anterior instala lo siguiente:
- El cliente TypeScript de SignalR, que permite al cliente enviar mensajes al servidor.
- Las definiciones de tipo de TypeScript para Node.js, que habilita la comprobación en tiempo de compilación de los tipos de Node.js.
Agregue el código resaltado al archivo src/index.ts:
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() { }El código anterior admite la recepción de mensajes desde el servidor. La clase
HubConnectionBuildercrea un generador para configurar la conexión al servidor. La funciónwithUrlconfigura la dirección URL del concentrador.SignalR permite el intercambio de mensajes entre un cliente y un servidor. Cada mensaje tiene un nombre específico. Por ejemplo, puede haber mensajes con el nombre
messageReceivedque pueden ejecutar la lógica responsable de mostrar el nuevo mensaje en la zona de mensajes. La escucha a un mensaje concreto se puede realizar mediante la funciónon. Se puede escuchar cualquier número de nombres de mensaje. También se pueden pasar parámetros al mensaje, como el nombre del autor y el contenido del mensaje recibido. Una vez que el cliente recibe un mensaje, se crea un elementodivcon el nombre del autor y el contenido del mensaje en su atributoinnerHTML. Se agrega al elementodivprincipal que muestra los mensajes.Ahora que el cliente puede recibir mensajes, debe configurarlo para poder enviarlos. Agregue el código resaltado al archivo src/index.ts:
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 = ""); }El envío de mensajes a través de la conexión de WebSockets requiere llamar al método
send. El primer parámetro del método es el nombre del mensaje. Los datos del mensaje se encuentran en los otros parámetros. En este ejemplo, se envía al servidor un mensaje identificado comonewMessage. El mensaje está formado por el nombre de usuario y la entrada del usuario desde un cuadro de texto. Si el envío funciona, se borra el valor del cuadro de texto.Agregue el método
NewMessagea la claseChatHub: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); } } }El código anterior difunde los mensajes recibidos a todos los usuarios conectados, una vez que el servidor los recibe. No es necesario tener un método
ongenérico para recibir todos los mensajes. Basta con un método que tenga el nombre del mensaje.En este ejemplo, el cliente de TypeScript envía un mensaje que se identifica como
newMessage. El métodoNewMessagede C# espera los datos enviados por el cliente. Se realiza una llamada a SendAsync de Clients.All. Los mensajes recibidos se envían a todos los clientes conectados al concentrador.
Prueba de la aplicación
Confirme que la aplicación funciona con los pasos siguientes.
Ejecute Webpack en modo release. Desde la ventana Consola del Administrador de paquetes, ejecute el comando siguiente en la raíz del proyecto. Si no está en la raíz del proyecto, escriba
cd SignalRWebPackantes de introducir el comando.npm run releaseEste comando genera la entrega de los recursos del lado cliente al ejecutar la aplicación. Los recursos se colocan en la carpeta wwwroot.
Webpack ha completado las tareas siguientes:
- Purgar el contenido del directorio wwwroot.
- Convertir el lenguaje TypeScript en JavaScript, proceso conocido como transpilación.
- Alterar el código JavaScript generado para reducir el tamaño del archivo, proceso conocido como minificación.
- Copiar los archivos JavaScript, CSS y HTML procesados desde src en el directorio wwwroot.
- Insertar los elementos siguientes en el archivo wwwroot/index.html:
- Etiqueta
<link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta</head>de cierre. - Etiqueta
<script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente antes de la etiqueta</body>de cierre.
- Etiqueta
Seleccione Depurar > Iniciar sin depurar para iniciar la aplicación en un explorador sin adjuntar el depurador. El archivo wwwroot/index.html se entrega en
http://localhost:<port_number>.Si obtiene errores de compilación, intente cerrar y volver a abrir la solución.
Abra otra instancia del explorador (sirve cualquiera). Pegue la dirección URL en la barra de direcciones.
Elija un explorador, escriba algo en el cuadro de texto Mensaje y haga clic en el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.

Requisitos previos
- Visual Studio 2019 con la carga de trabajo ASP.NET y desarrollo web
- .NET Core SDK 2.2 o posterior
- Node.js con npm
Creación de la aplicación web ASP.NET Core
Configure Visual Studio para buscar npm en la variable de entorno PATH. De forma predeterminada, Visual Studio usa la versión de npm que se encuentra en su directorio de instalación. Siga estas instrucciones en Visual Studio:
Vaya a Herramientas > Opciones > Proyectos y soluciones > Administración de paquetes web > Herramientas web externas.
Seleccione la entrada $(PATH) en la lista. Haga clic en la flecha arriba para mover la entrada a la segunda posición de la lista.

Se ha completado la configuración de Visual Studio. Es el momento de crear el proyecto.
- Use la opción de menú Archivo > Nuevo > Proyecto y seleccione la plantilla Aplicación web ASP.NET Core.
- Asigne el nombre SignalRWebPack al proyecto y seleccione Crear.
- Seleccione .NET Core en la lista desplegable de plataforma de destino y ASP.NET Core 2.2 en la lista desplegable del selector de plataforma. Seleccione la plantilla Vacía y Crear.
Configuración de Webpack y TypeScript
Los pasos siguientes permiten configurar la conversión de TypeScript a JavaScript y la agrupación de los recursos del lado cliente.
Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:
npm init -yAgregue la propiedad resaltada al archivo package.json:
{ "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" }Si establece la propiedad
privateentrue, evitará las advertencias de la instalación de paquetes en el paso siguiente.Instale los paquetes npm necesarios. Ejecute el comando siguiente desde la raíz del proyecto:
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.3Algunos detalles del comando para tener en cuenta:
- En cada nombre de paquete, un número de versión sigue al signo
@. npm instala esas versiones de paquete específicas. - La opción
-Edeshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de versionamiento semántico en package.json. Por ejemplo, se usa"webpack": "4.29.3"en lugar de"webpack": "^4.29.3". Esta opción impide actualizaciones no deseadas a versiones más recientes del paquete.
Consulte la documentación de npm-install para obtener más detalles.
- En cada nombre de paquete, un número de versión sigue al signo
Reemplace la propiedad
scriptsdel archivo package.json por el código siguiente:"scripts": { "build": "webpack --mode=development --watch", "release": "webpack --mode=production", "publish": "npm run release && dotnet publish -c Release" },Más detalles sobre los scripts:
build: agrupa los recursos del lado cliente en modo de desarrollo y supervisa los cambios del archivo. El monitor de archivos hace que la agrupación se vuelva a generar cada vez que cambia un archivo del proyecto. La opciónmodedeshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Usebuildúnicamente durante el desarrollo.release: agrupa los recursos del lado cliente en modo de producción.publish: ejecuta el scriptreleasepara agrupar los recursos del lado cliente en modo de producción. Llama al comando publish de la CLI de .NET Core para publicar la aplicación.
Cree un archivo denominado webpack.config.js, en la raíz del proyecto, con el código siguiente:
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" }) ] };El archivo anterior configura la compilación de Webpack. Algunos detalles de configuración para tener en cuenta:
- La propiedad
outputinvalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot. - La matriz
resolve.extensionsincluye .js para importar el código JavaScript del cliente de SignalR.
- La propiedad
Cree un src directorio en la raíz del proyecto para almacenar los recursos del lado cliente del proyecto.
Cree src/index.html con el marcado siguiente.
<!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>El código HTML anterior define el marcado reutilizable de la página principal.
Cree un directorio src/css. Su objetivo es almacenar los archivos .css del proyecto.
Cree src/css/main.css con el marcado siguiente:
*, *::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; }El archivo main.css anterior aplica estilo a la aplicación.
Cree src/tsconfig.json con el JSON siguiente:
{ "compilerOptions": { "target": "es5" } }El código anterior configura el compilador de TypeScript para generar JavaScript compatible con ECMAScript 5.
Cree src/index.ts con el código siguiente:
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() { }El elemento TypeScript anterior recupera las referencias a elementos DOM y adjunta dos controladores de eventos:
keyup: este evento se desencadena cuando el usuario escribe en el cuadro de textotbMessage. La funciónsendse llama cuando el usuario presiona la tecla Entrar.click: este evento se desencadena cuando el usuario hace clic en el botón Enviar. Se llama a la funciónsend.
Configuración de la aplicación ASP.NET Core
El código proporcionado en el método
Startup.Configuremuestra Hello World! . Reemplace la llamada al métodoapp.Runpor las llamadas a UseDefaultFiles y UseStaticFiles.app.UseDefaultFiles(); app.UseStaticFiles();El código anterior permite que el servidor busque y proporcione el archivo index.html, con independencia de que el usuario escriba su dirección URL completa o la dirección URL raíz de la aplicación web.
Llame a AddSignalR en
Startup.ConfigureServices. Esta acción agrega los servicios SignalR al proyecto.services.AddSignalR();Asigne una ruta /hub al concentrador
ChatHub. Agregue la línea siguiente al final deStartup.Configure:app.UseSignalR(options => { options.MapHub<ChatHub>("/hub"); });Cree un directorio denominado Hubs en la raíz del proyecto. Su objetivo es almacenar el concentrador de SignalR, que se crea en el paso siguiente.
Cree el concentrador Hubs/ChatHub.cs con el código siguiente:
using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace SignalRWebPack.Hubs { public class ChatHub : Hub { } }Agregue el código siguiente en la parte superior del archivo Startup.cs para resolver la referencia a
ChatHub:using SignalRWebPack.Hubs;
Habilitar la comunicación entre cliente y servidor
Actualmente, en la aplicación se muestra un formulario simple para enviar mensajes. Al intentar hacer algo no sucede nada. El servidor está escuchando en una ruta específica, pero no hace nada con los mensajes enviados.
Ejecute el comando siguiente en la raíz del proyecto:
npm install @aspnet/signalrEl comando anterior instala el cliente TypeScript de SignalR, que permite al cliente enviar mensajes al servidor.
Agregue el código resaltado al archivo src/index.ts:
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() { }El código anterior admite la recepción de mensajes desde el servidor. La clase
HubConnectionBuildercrea un generador para configurar la conexión al servidor. La funciónwithUrlconfigura la dirección URL del concentrador.SignalR permite el intercambio de mensajes entre un cliente y un servidor. Cada mensaje tiene un nombre específico. Por ejemplo, puede haber mensajes con el nombre
messageReceivedque pueden ejecutar la lógica responsable de mostrar el nuevo mensaje en la zona de mensajes. La escucha a un mensaje concreto se puede realizar mediante la funciónon. Puede escuchar a cualquier número de nombres de mensaje. También se pueden pasar parámetros al mensaje, como el nombre del autor y el contenido del mensaje recibido. Una vez que el cliente recibe un mensaje, se crea un elementodivcon el nombre del autor y el contenido del mensaje en su atributoinnerHTML. El nuevo mensaje se agrega al elementodivprincipal que muestra los mensajes.Ahora que el cliente puede recibir mensajes, debe configurarlo para poder enviarlos. Agregue el código resaltado al archivo src/index.ts:
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 = ""); }El envío de mensajes a través de la conexión de WebSockets requiere llamar al método
send. El primer parámetro del método es el nombre del mensaje. Los datos del mensaje se encuentran en los otros parámetros. En este ejemplo, se envía al servidor un mensaje identificado comonewMessage. El mensaje está formado por el nombre de usuario y la entrada del usuario desde un cuadro de texto. Si el envío funciona, se borra el valor del cuadro de texto.Agregue el método
NewMessagea la claseChatHub: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); } } }El código anterior difunde los mensajes recibidos a todos los usuarios conectados, una vez que el servidor los recibe. No es necesario tener un método
ongenérico para recibir todos los mensajes. Basta con un método que tenga el nombre del mensaje.En este ejemplo, el cliente de TypeScript envía un mensaje que se identifica como
newMessage. El métodoNewMessagede C# espera los datos enviados por el cliente. Se realiza una llamada a SendAsync de Clients.All. Los mensajes recibidos se envían a todos los clientes conectados al concentrador.
Prueba de la aplicación
Confirme que la aplicación funciona con los pasos siguientes.
Ejecute Webpack en modo release. Desde la ventana Consola del Administrador de paquetes, ejecute el comando siguiente en la raíz del proyecto. Si no está en la raíz del proyecto, escriba
cd SignalRWebPackantes de introducir el comando.npm run releaseEste comando genera la entrega de los recursos del lado cliente al ejecutar la aplicación. Los recursos se colocan en la carpeta wwwroot.
Webpack ha completado las tareas siguientes:
- Purgar el contenido del directorio wwwroot.
- Convertir el lenguaje TypeScript en JavaScript, proceso conocido como transpilación.
- Alterar el código JavaScript generado para reducir el tamaño del archivo, proceso conocido como minificación.
- Copiar los archivos JavaScript, CSS y HTML procesados desde src en el directorio wwwroot.
- Insertar los elementos siguientes en el archivo wwwroot/index.html:
- Etiqueta
<link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta</head>de cierre. - Etiqueta
<script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente antes de la etiqueta</body>de cierre.
- Etiqueta
Seleccione Depurar > Iniciar sin depurar para iniciar la aplicación en un explorador sin adjuntar el depurador. El archivo wwwroot/index.html se entrega en
http://localhost:<port_number>.Abra otra instancia del explorador (sirve cualquiera). Pegue la dirección URL en la barra de direcciones.
Elija un explorador, escriba algo en el cuadro de texto Mensaje y haga clic en el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.
