Tutorial: Introducción a ASP.NET Core SignalR mediante TypeScript y Webpack

Nota:

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión .NET 8 de este artículo.

Por Sébastien Sougnez

En este tutorial se describe el uso de Webpack en una aplicación web ASP.NET Core SignalR para unir y crear un cliente escrito en TypeScript. Webpack permite a los desarrolladores agrupar y compilar los recursos del lado cliente de una aplicación web.

En este tutorial aprenderá a:

  • Crear una aplicación SignalR de ASP.NET Core
  • Configurar el servidor SignalR
  • Configuración de una canalización de compilación mediante Webpack
  • Configurar el cliente de TypeScript para SignalR
  • Habilitar la comunicación entre el cliente y el servidor

Vea o descargue el código de ejemplo (cómo descargarlo)

Requisitos previos

Creación de la aplicación web ASP.NET Core

De forma predeterminada, Visual Studio usa la versión de npm que se encuentra en su directorio de instalación. Para configurar Visual Studio a fin de buscar npm en la variable de entorno PATH:

Inicie Visual Studio. En la ventana de inicio, seleccione Continuar sin código.

  1. Vaya a Herramientas>Opciones>Proyectos y soluciones>Administración de paquetes web>Herramientas web externas.

  2. Seleccione la entrada $(PATH) en la lista. Seleccione la flecha arriba para mover la entrada a la segunda posición de la lista y seleccione Aceptar:

    Configuración de Visual Studio.

Para crear una aplicación web de ASP.NET Core:

  1. Use la opción de menú Archivo>Nuevo>Proyecto y seleccione la plantilla ASP.NET Core vacío. Seleccione Next (Siguiente).
  2. Asigne el nombre SignalRWebpack al proyecto y seleccione Crear.
  3. Seleccione .NET 8.0 (Compatibilidad a largo plazo) en la lista desplegable Framework. Seleccione Crear.

Agregue el paquete NuGet Microsoft.TypeScript.MSBuild al proyecto:

  1. En el Explorador de soluciones, 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.MSBuild y, luego, seleccione 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 del servidor

En esta sección, configurará la aplicación web ASP.NET Core para enviar y recibir mensajes SignalR.

  1. En Program.cs, llame a AddSignalR:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddSignalR();
    
  2. De nuevo, en Program.cs, llame a UseDefaultFiles y UseStaticFiles:

    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    

    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.

  3. Cree un directorio denominado Hubs en la raíz del proyecto, SignalRWebpack/, para la clase de centro SignalR.

  4. Cree un archivo. Hubs/ChatHub.cs, con el código siguiente:

    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);
    }
    

    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 on gené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étodo NewMessage de C# espera los datos enviados por el cliente.
    • Se realiza una llamada a SendAsync en Clients.All.
    • Los mensajes recibidos se envían a todos los clientes conectados al concentrador.
  5. Agregue la instrucción using siguiente en la parte superior de Program.cs para resolver la referencia a ChatHub:

    using SignalRWebpack.Hubs;
    
  6. En Program.cs, asigne la ruta /hub al centro ChatHub. Reemplace el código que muestra Hello World! por el siguiente:

    app.MapHub<ChatHub>("/hub");
    

Configurar el cliente

En esta sección, creará un proyecto de Node.js para convertir TypeScript en JavaScript y agrupar recursos del lado cliente, incluidos HTML y CSS, mediante Webpack.

  1. Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:

    npm init -y
    
  2. Agregue 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 private en true, evitará las advertencias de la instalación de paquetes en el paso siguiente.

  3. Instale los paquetes npm necesarios. Ejecute el comando siguiente desde la raíz del proyecto:

    npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli
    

    La opción -E deshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de control de versiones semántico en package.json. Por ejemplo, se usa "webpack": "5.76.1" en lugar de "webpack": "^5.76.1". Esta opción impide actualizaciones no deseadas a versiones más recientes del paquete.

    Para más información, vea la documentación de npm-install.

  4. Reemplace la propiedad scripts del 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"
    },
    

    Se definen los siguientes 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ón mode deshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Use build únicamente durante el desarrollo.
    • release: agrupa los recursos del lado cliente en modo de producción.
    • publish: ejecuta el script release para agrupar los recursos del lado cliente en modo de producción. Llama al comando publish de la CLI de .NET para publicar la aplicación.
  5. 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 el proceso de compilación de Webpack:

    • La propiedad output invalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot.
    • La matriz resolve.extensions incluye .js para importar el código JavaScript del cliente de SignalR.
  6. Cree un directorio denominado src en la raíz del proyecto, SignalRWebpack/, para el código de cliente.

  7. Copie el directorio src y sus contenidos del proyecto de ejemplo en la raíz del proyecto. El directorio src contiene los siguientes archivos:

    • index.html, que define el marcado reutilizable de la página principal:

      <!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, que proporciona estilos CSS para la página principal:

      *,
      *::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, que configura el compilador de TypeScript para generar JavaScript compatible 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 = ""));
      }
      

      En el código anterior se recuperan las referencias a elementos DOM y se adjuntan dos controladores de eventos:

      • keyup: se desencadena cuando el usuario escribe en el cuadro de texto tbMessage y llama a la función send cuando el usuario presiona la tecla Entrar.
      • click: se desencadena cuando el usuario selecciona el botón Enviar y se llama a la función send.

      La clase HubConnectionBuilder crea un generador para configurar la conexión al servidor. La función withUrl configura 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 messageReceived que 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ón on. 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 elemento div con el nombre del autor y el contenido del mensaje en su atributo innerHTML. Se agrega al elemento div principal que muestra los mensajes.

      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 como newMessage. 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.

  8. Ejecute el comando siguiente en la raíz del proyecto:

    npm i @microsoft/signalr @types/node
    

    El 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.

Prueba de la aplicación

Confirme que la aplicación funciona con los pasos siguientes:

  1. Ejecute Webpack en modo release. Desde la ventana Consola del Administrador de paquetes, ejecute el comando siguiente en la raíz del proyecto.

    npm run release
    

    Este 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.
    • Se han insertado los elementos siguientes en el archivo wwwroot/index.html:
      • Una etiqueta <link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta </head> de cierre.
      • Una etiqueta <script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente después de la etiqueta </title> de cierre.
  2. 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 https://localhost:<port>.

    Si hay errores de compilación, intente cerrar y volver a abrir la solución.

  3. Abra otra instancia del explorador (cualquier explorador) y pegue la dirección URL en la barra de direcciones.

  4. Elija un explorador, escriba algo en el cuadro de texto Mensaje y seleccione el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.

Mensaje mostrado en las dos ventanas del explorador

Pasos siguientes

Recursos adicionales

En este tutorial se describe el uso de Webpack en una aplicación web ASP.NET Core SignalR para unir y crear un cliente escrito en TypeScript. Webpack permite a los desarrolladores agrupar y compilar los recursos del lado cliente de una aplicación web.

En este tutorial aprenderá a:

  • Crear una aplicación SignalR de ASP.NET Core
  • Configurar el servidor SignalR
  • Configuración de una canalización de compilación mediante Webpack
  • Configurar el cliente de TypeScript para SignalR
  • Habilitar la comunicación entre el cliente y el servidor

Vea o descargue el código de ejemplo (cómo descargarlo)

Requisitos previos

Creación de la aplicación web ASP.NET Core

De forma predeterminada, Visual Studio usa la versión de npm que se encuentra en su directorio de instalación. Para configurar Visual Studio a fin de buscar npm en la variable de entorno PATH:

Inicie Visual Studio. En la ventana de inicio, seleccione Continuar sin código.

  1. Vaya a Herramientas>Opciones>Proyectos y soluciones>Administración de paquetes web>Herramientas web externas.

  2. Seleccione la entrada $(PATH) en la lista. Seleccione la flecha arriba para mover la entrada a la segunda posición de la lista y seleccione Aceptar:

    Configuración de Visual Studio.

Para crear una aplicación web de ASP.NET Core:

  1. Use la opción de menú Archivo>Nuevo>Proyecto y seleccione la plantilla ASP.NET Core vacío. Seleccione Next (Siguiente).
  2. Asigne el nombre SignalRWebpack al proyecto y seleccione Crear.
  3. Seleccione .NET 7.0 (Standard Term Support) en la lista desplegable Marco. Seleccione Crear.

Agregue el paquete NuGet Microsoft.TypeScript.MSBuild al proyecto:

  1. En el Explorador de soluciones, 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.MSBuild y, luego, seleccione 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 del servidor

En esta sección, configurará la aplicación web ASP.NET Core para enviar y recibir mensajes SignalR.

  1. En Program.cs, llame a AddSignalR:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddSignalR();
    
  2. De nuevo, en Program.cs, llame a UseDefaultFiles y UseStaticFiles:

    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    

    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.

  3. Cree un directorio denominado Hubs en la raíz del proyecto, SignalRWebpack/, para la clase de centro SignalR.

  4. Cree un archivo. Hubs/ChatHub.cs, con el código siguiente:

    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);
    }
    

    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 on gené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étodo NewMessage de C# espera los datos enviados por el cliente.
    • Se realiza una llamada a SendAsync en Clients.All.
    • Los mensajes recibidos se envían a todos los clientes conectados al concentrador.
  5. Agregue la instrucción using siguiente en la parte superior de Program.cs para resolver la referencia a ChatHub:

    using SignalRWebpack.Hubs;
    
  6. En Program.cs, asigne la ruta /hub al centro ChatHub. Reemplace el código que muestra Hello World! por el siguiente:

    app.MapHub<ChatHub>("/hub");
    

Configurar el cliente

En esta sección, creará un proyecto de Node.js para convertir TypeScript en JavaScript y agrupar recursos del lado cliente, incluidos HTML y CSS, mediante Webpack.

  1. Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:

    npm init -y
    
  2. Agregue 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 private en true, evitará las advertencias de la instalación de paquetes en el paso siguiente.

  3. Instale los paquetes npm necesarios. Ejecute el comando siguiente desde la raíz del proyecto:

    npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli
    

    La opción -E deshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de control de versiones semántico en package.json. Por ejemplo, se usa "webpack": "5.76.1" en lugar de "webpack": "^5.76.1". Esta opción impide actualizaciones no deseadas a versiones más recientes del paquete.

    Para más información, vea la documentación de npm-install.

  4. Reemplace la propiedad scripts del 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"
    },
    

    Se definen los siguientes 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ón mode deshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Use build únicamente durante el desarrollo.
    • release: agrupa los recursos del lado cliente en modo de producción.
    • publish: ejecuta el script release para agrupar los recursos del lado cliente en modo de producción. Llama al comando publish de la CLI de .NET para publicar la aplicación.
  5. 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 el proceso de compilación de Webpack:

    • La propiedad output invalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot.
    • La matriz resolve.extensions incluye .js para importar el código JavaScript del cliente de SignalR.
  6. Copie el directorio src y sus contenidos del proyecto de ejemplo en la raíz del proyecto. El directorio src contiene los siguientes archivos:

    • index.html, que define el marcado reutilizable de la página principal:

      <!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, que proporciona estilos CSS para la página principal:

      *,
      *::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, que configura el compilador de TypeScript para generar JavaScript compatible 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 = ""));
      }
      

      En el código anterior se recuperan las referencias a elementos DOM y se adjuntan dos controladores de eventos:

      • keyup: se desencadena cuando el usuario escribe en el cuadro de texto tbMessage y llama a la función send cuando el usuario presiona la tecla Entrar.
      • click: se desencadena cuando el usuario selecciona el botón Enviar y se llama a la función send.

      La clase HubConnectionBuilder crea un generador para configurar la conexión al servidor. La función withUrl configura 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 messageReceived que 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ón on. 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 elemento div con el nombre del autor y el contenido del mensaje en su atributo innerHTML. Se agrega al elemento div principal que muestra los mensajes.

      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 como newMessage. 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.

  7. Ejecute el comando siguiente en la raíz del proyecto:

    npm i @microsoft/signalr @types/node
    

    El 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.

Prueba de la aplicación

Confirme que la aplicación funciona con los pasos siguientes:

  1. Ejecute Webpack en modo release. Desde la ventana Consola del Administrador de paquetes, ejecute el comando siguiente en la raíz del proyecto.

    npm run release
    

    Este 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.
    • Se han insertado los elementos siguientes en el archivo wwwroot/index.html:
      • Una etiqueta <link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta </head> de cierre.
      • Una etiqueta <script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente después de la etiqueta </title> de cierre.
  2. 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 https://localhost:<port>.

    Si hay errores de compilación, intente cerrar y volver a abrir la solución.

  3. Abra otra instancia del explorador (cualquier explorador) y pegue la dirección URL en la barra de direcciones.

  4. Elija un explorador, escriba algo en el cuadro de texto Mensaje y seleccione el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.

Mensaje mostrado en las dos ventanas del explorador

Pasos siguientes

Recursos adicionales

En este tutorial se describe el uso de Webpack en una aplicación web ASP.NET Core SignalR para unir y crear un cliente escrito en TypeScript. Webpack permite a los desarrolladores agrupar y compilar los recursos del lado cliente de una aplicación web.

En este tutorial aprenderá a:

  • Crear una aplicación SignalR de ASP.NET Core
  • Configurar el servidor SignalR
  • Configuración de una canalización de compilación mediante Webpack
  • Configurar el cliente de TypeScript para SignalR
  • Habilitar la comunicación entre el cliente y el servidor

Vea o descargue el código de ejemplo (cómo descargarlo)

Requisitos previos

Creación de la aplicación web ASP.NET Core

De forma predeterminada, Visual Studio usa la versión de npm que se encuentra en su directorio de instalación. Para configurar Visual Studio a fin de buscar npm en la variable de entorno PATH:

  1. Inicie Visual Studio. En la ventana de inicio, seleccione Continuar sin código.

  2. Vaya a Herramientas>Opciones>Proyectos y soluciones>Administración de paquetes web>Herramientas web externas.

  3. Seleccione la entrada $(PATH) en la lista. Seleccione la flecha arriba para mover la entrada a la segunda posición de la lista y seleccione Aceptar:

    Configuración de Visual Studio.

Para crear una aplicación web de ASP.NET Core:

  1. Use la opción de menú Archivo>Nuevo>Proyecto y seleccione la plantilla ASP.NET Core vacío. Seleccione Next (Siguiente).
  2. Asigne el nombre SignalRWebpack al proyecto y seleccione Crear.
  3. Seleccione .NET 6.0 (Long Term Support) en la lista desplegable Marco. Seleccione Crear.

Agregue el paquete NuGet Microsoft.TypeScript.MSBuild al proyecto:

  1. En el Explorador de soluciones, 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.MSBuild y, luego, seleccione 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 del servidor

En esta sección, configurará la aplicación web ASP.NET Core para enviar y recibir mensajes SignalR.

  1. En Program.cs, llame a AddSignalR:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddSignalR();
    
  2. De nuevo, en Program.cs, llame a UseDefaultFiles y UseStaticFiles:

    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    

    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.

  3. Cree un directorio denominado Hubs en la raíz del proyecto, SignalRWebpack/, para la clase de centro SignalR.

  4. Cree un archivo. Hubs/ChatHub.cs, con el código siguiente:

    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);
    }
    

    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 on gené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étodo NewMessage de C# espera los datos enviados por el cliente. Se realiza una llamada a SendAsync en Clients.All. Los mensajes recibidos se envían a todos los clientes conectados al concentrador.

  5. Agregue la instrucción using siguiente en la parte superior de Program.cs para resolver la referencia a ChatHub:

    using SignalRWebpack.Hubs;
    
  6. En Program.cs, asigne la ruta /hub al centro ChatHub. Reemplace el código que muestra Hello World! por el siguiente:

    app.MapHub<ChatHub>("/hub");
    

Configurar el cliente

En esta sección, creará un proyecto de Node.js para convertir TypeScript en JavaScript y agrupar recursos del lado cliente, incluidos HTML y CSS, mediante Webpack.

  1. Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:

    npm init -y
    
  2. Agregue 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 private en true, evitará las advertencias de la instalación de paquetes en el paso siguiente.

  3. Instale los paquetes npm necesarios. Ejecute el comando siguiente desde la raíz del proyecto:

    npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli
    

    La opción -E deshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de control de versiones semántico en package.json. Por ejemplo, se usa "webpack": "5.70.0" en lugar de "webpack": "^5.70.0". Esta opción impide actualizaciones no deseadas a versiones más recientes del paquete.

    Para más información, vea la documentación de npm-install.

  4. Reemplace la propiedad scripts del 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"
    },
    

    Se definen los siguientes 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ón mode deshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Use build únicamente durante el desarrollo.
    • release: agrupa los recursos del lado cliente en modo de producción.
    • publish: ejecuta el script release para agrupar los recursos del lado cliente en modo de producción. Llama al comando publish de la CLI de .NET para publicar la aplicación.
  5. 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 el proceso de compilación de Webpack:

    • La propiedad output invalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot.
    • La matriz resolve.extensions incluye .js para importar el código JavaScript del cliente de SignalR.
  6. Copie el directorio src y sus contenidos del proyecto de ejemplo en la raíz del proyecto. El directorio src contiene los siguientes archivos:

    • index.html, que define el marcado reutilizable de la página principal:

      <!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, que proporciona estilos CSS para la página principal:

      *,
      *::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, que configura el compilador de TypeScript para generar JavaScript compatible 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 = ""));
      }
      

    En el código anterior se recuperan las referencias a elementos DOM y se adjuntan dos controladores de eventos:

    • keyup: se desencadena cuando el usuario escribe en el cuadro de texto tbMessage y llama a la función send cuando el usuario presiona la tecla Entrar.
    • click: se desencadena cuando el usuario selecciona el botón Enviar y se llama a la función send.

    La clase HubConnectionBuilder crea un generador para configurar la conexión al servidor. La función withUrl configura 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 messageReceived que 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ón on. 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 elemento div con el nombre del autor y el contenido del mensaje en su atributo innerHTML. Se agrega al elemento div principal que muestra los mensajes.

    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 como newMessage. 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.

  7. Ejecute el comando siguiente en la raíz del proyecto:

    npm i @microsoft/signalr @types/node
    

    El 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.

Prueba de la aplicación

Confirme que la aplicación funciona con los pasos siguientes:

  1. 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 SignalRWebpack antes de introducir el comando.

    npm run release
    

    Este 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.
    • Se han insertado los elementos siguientes en el archivo wwwroot/index.html:
      • Una etiqueta <link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta </head> de cierre.
      • Una etiqueta <script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente después de la etiqueta </title> de cierre.
  2. 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 https://localhost:<port>.

    Si obtiene errores de compilación, intente cerrar y volver a abrir la solución.

  3. Abra otra instancia del explorador (cualquier explorador) y pegue la dirección URL en la barra de direcciones.

  4. Elija un explorador, escriba algo en el cuadro de texto Mensaje y seleccione el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.

Mensaje mostrado en las dos ventanas del explorador

Pasos siguientes

Recursos adicionales

En este tutorial se describe el uso de Webpack en una aplicación web ASP.NET Core SignalR para unir y crear un cliente escrito en TypeScript. Webpack permite a los desarrolladores agrupar y compilar los recursos del lado cliente de una aplicación web.

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

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:

  1. Inicie Visual Studio. En la ventana de inicio, seleccione Continuar sin código.

  2. Vaya a Herramientas>Opciones>Proyectos y soluciones>Administración de paquetes web>Herramientas web externas.

  3. 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.

    Configuración de Visual Studio.

Se ha completado la configuración de Visual Studio.

  1. Use la opción de menú Archivo>Nuevo>Proyecto y seleccione la plantilla Aplicación web ASP.NET Core. Seleccione Next (Siguiente).
  2. Asigne el nombre *SignalRWebPac`` al proyecto y seleccione Crear.
  3. 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:

  1. 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.MSBuild y 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.

  1. Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:

    npm init -y
    
  2. Agregue 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 private en true, evitará las advertencias de la instalación de paquetes en el paso siguiente.

  3. 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.10
    

    Algunos 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 -E deshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de control de versiones semántico en *packagejson. 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.

  4. Reemplace la propiedad scripts del 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ón mode deshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Use build únicamente durante el desarrollo.
    • release: agrupa los recursos del lado cliente en modo de producción.
    • publish: ejecuta el script release para 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.
  5. 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 output invalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot.
    • La matriz resolve.extensions incluye .js para importar el código JavaScript del cliente de SignalR.
  6. Cree un src directorio en la raíz del proyecto para almacenar los recursos del lado cliente del proyecto.

  7. 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.

  8. Cree un directorio src/css. Su objetivo es almacenar los archivos .css del proyecto.

  9. 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.

  10. Cree src/tsconfig.json con el siguiente JSON:

    {
      "compilerOptions": {
        "target": "es5"
      }
    }
    

    El código anterior configura el compilador de TypeScript para generar JavaScript compatible con ECMAScript 5.

  11. Cree el archivo src/index.ts con el siguiente código:

    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 en el cuadro de texto tbMessage. La función send se llama cuando el usuario presiona la tecla Entrar.
    • click: este evento se desencadena cuando el usuario selecciona el botón Enviar. Se llama a la función send.

Configuración de la aplicación

  1. En Startup.Configure, agregue llamadas a UseDefaultFiles(IApplicationBuilder) y 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");
        });
            
    }
    

    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.

  2. Al final de Startup.Configure, asigne una ruta /hub al centro ChatHub. Reemplace el código que muestra Hola mundo por la línea siguiente:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>("/hub");
    });
    
  3. En Startup.ConfigureServices, llame a AddSignalR.

    services.AddSignalR();
    
  4. Cree un directorio denominado Hubs en la raíz del proyecto SignalRWebPack/ para almacenar el centro SignalR.

  5. 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
        {
        }
    }
    
  6. Agregue la instrucción using 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

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.

  1. Ejecute el comando siguiente en la raíz del proyecto:

    npm i @microsoft/signalr @types/node
    

    El 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.
  2. 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 HubConnectionBuilder crea un generador para configurar la conexión al servidor. La función withUrl configura 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 messageReceived que 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ón on. 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 elemento div con el nombre del autor y el contenido del mensaje en su atributo innerHTML. Se agrega al elemento div principal que muestra los mensajes.

  3. 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 como newMessage. 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.

  4. Agregue el método NewMessage a la clase ChatHub:

    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 on gené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étodo NewMessage de C# espera los datos enviados por el cliente. Se realiza una llamada a SendAsync en 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.

  1. 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 SignalRWebPack antes de introducir el comando.

    npm run release
    

    Este 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.
    • Se han insertado los elementos siguientes en el archivo wwwroot/index.html:
      • Una etiqueta <link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta </head> de cierre.
      • Una etiqueta <script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente después de la etiqueta </title> de cierre.
  2. 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.

  3. Abra otra instancia del explorador (sirve cualquiera). Pegue la dirección URL en la barra de direcciones.

  4. Elija un explorador, escriba algo en el cuadro de texto Mensaje y seleccione el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.

Mensaje mostrado en las dos ventanas del explorador

Recursos adicionales

En este tutorial se describe el uso de Webpack en una aplicación web ASP.NET Core SignalR para unir y crear un cliente escrito en TypeScript. Webpack permite a los desarrolladores agrupar y compilar los recursos del lado cliente de una aplicación web.

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

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:

  1. Vaya a Herramientas>Opciones>Proyectos y soluciones>Administración de paquetes web>Herramientas web externas.

  2. Seleccione la entrada $(PATH) en la lista. Seleccione la flecha arriba para mover la entrada a la segunda posición de la lista.

    Configuración de Visual Studio

Se ha completado la configuración de Visual Studio. Es el momento de crear el proyecto.

  1. Use la opción de menú Archivo>Nuevo>Proyecto y seleccione la plantilla Aplicación web ASP.NET Core.
  2. Asigne el nombre *SignalRWebPack` al proyecto y seleccione Crear.
  3. 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.

  1. Ejecute el comando siguiente en la raíz del proyecto para crear un archivo package.json:

    npm init -y
    
  2. Agregue 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 private en true, evitará las advertencias de la instalación de paquetes en el paso siguiente.

  3. 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.3
    

    Algunos 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 -E deshabilita el comportamiento predeterminado de npm de escribir operadores de intervalo de control de versiones semántico en *packagejson. 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.

  4. Reemplace la propiedad scripts del 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ón mode deshabilita las optimizaciones de producción, como la agitación del árbol y la minificación. Use build únicamente durante el desarrollo.
    • release: agrupa los recursos del lado cliente en modo de producción.
    • publish: ejecuta el script release para 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.
  5. 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 output invalida el valor predeterminado de dist. En su lugar, la agrupación se genera en el directorio wwwroot.
    • La matriz resolve.extensions incluye .js para importar el código JavaScript del cliente de SignalR.
  6. Cree un src directorio en la raíz del proyecto para almacenar los recursos del lado cliente del proyecto.

  7. 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.

  8. Cree un directorio src/css. Su objetivo es almacenar los archivos .css del proyecto.

  9. 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.

  10. Cree src/tsconfig.json con el siguiente JSON:

    {
      "compilerOptions": {
        "target": "es5"
      }
    }
    

    El código anterior configura el compilador de TypeScript para generar JavaScript compatible con ECMAScript 5.

  11. Cree el archivo src/index.ts con el siguiente código:

    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 texto tbMessage. La función send se llama cuando el usuario presiona la tecla Entrar.
    • click: este evento se desencadena cuando el usuario selecciona el botón Enviar. Se llama a la función send.

Configuración de la aplicación ASP.NET Core

  1. El código proporcionado en el método Startup.Configure muestra Hello World! . Reemplace la llamada de método app.Run por llamadas a UseDefaultFiles(IApplicationBuilder) y UseStaticFiles(IApplicationBuilder).

    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.

  2. Llame a AddSignalR en Startup.ConfigureServices. Esta acción agrega los servicios SignalR al proyecto.

    services.AddSignalR();
    
  3. Asigne una ruta /hub al concentrador ChatHub. Agregue la línea siguiente al final de Startup.Configure:

    app.UseSignalR(options =>
    {
        options.MapHub<ChatHub>("/hub");
    });
    
  4. 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.

  5. 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
        {
        }
    }
    
  6. 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.

  1. Ejecute el comando siguiente en la raíz del proyecto:

    npm install @aspnet/signalr
    

    El comando anterior instala el cliente TypeScript de SignalR, que permite al cliente enviar mensajes al servidor.

  2. 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 HubConnectionBuilder crea un generador para configurar la conexión al servidor. La función withUrl configura 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 messageReceived que 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ón on. 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 elemento div con el nombre del autor y el contenido del mensaje en su atributo innerHTML. El nuevo mensaje se agrega al elemento div principal que muestra los mensajes.

  3. 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 como newMessage. 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.

  4. Agregue el método NewMessage a la clase ChatHub:

    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 on gené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étodo NewMessage de C# espera los datos enviados por el cliente. Se realiza una llamada a SendAsync en 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.

  1. 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 SignalRWebPack antes de introducir el comando.

    npm run release
    

    Este 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.
    • Se han insertado los elementos siguientes en el archivo wwwroot/index.html:
      • Una etiqueta <link>, que hace referencia al archivo wwwroot/main.<hash>.css. Esta etiqueta se coloca inmediatamente antes de la etiqueta </head> de cierre.
      • Una etiqueta <script>, que hace referencia al archivo wwwroot/main.<hash>.js minificado. Esta etiqueta se coloca inmediatamente después de la etiqueta </title> de cierre.
  2. 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>.

  3. Abra otra instancia del explorador (sirve cualquiera). Pegue la dirección URL en la barra de direcciones.

  4. Elija un explorador, escriba algo en el cuadro de texto Mensaje y seleccione el botón Enviar. El nombre de usuario único y el mensaje se muestran en las dos páginas al instante.

Mensaje mostrado en las dos ventanas del explorador

Recursos adicionales