ASP.NET Core SignalR es una biblioteca de Microsoft que, en particular, ofrece a los desarrolladores la posibilidad de incluir funciones en tiempo real en las aplicaciones web. Aunque lo primero que viene a la mente de forma natural cuando se oye hablar de “tiempo real” es un chat, puede aplicarse a un montón de casos de uso como juegos, encuestas en línea, cuadros de mando en tiempo real, aplicaciones colaborativas, etc. Aquí, en Redwerk, tenemos una gran experiencia con SignalR, y podemos decir con seguridad que es una biblioteca realmente potente y fácil de usar
Imaginemos que se enfrenta a una situación en la que su cliente tiene un cuadro de mandos de programación para un gran equipo, ¿cómo proporcionaría a los usuarios finales información actualizada sin obligarles a actualizar la página todo el tiempo? ¿O, por ejemplo, si utiliza Azure Media Services y necesita notificar a sus usuarios que el vídeo se ha procesado correctamente? La forma “mala” sería utilizar el sondeo. De hecho, el polling en sí mismo no es algo malo porque, por su naturaleza, es sólo una implementación de una llamada a un punto final. Sin embargo, el sondeo constante es un despilfarro, especialmente cuando hay que sondear algún punto final, que cada vez obtiene algo de la base de datos. Es un despilfarro en términos de recursos, de tráfico, de sus esfuerzos, y sin duda la mayoría de las peticiones no serán útiles. Ahí es donde entra en juego SignalR.
Como se menciona en la documentación oficial, SignalR soporta varias técnicas para manejar las comunicaciones en tiempo real:
- WebSockets: es la forma más óptima ya que es el único transporte que establece una verdadera conexión persistente y bidireccional. Si tanto el cliente como el servidor soportan este mecanismo, se utilizará.
- Eventos enviados por el servidor se utiliza cuando los WebSockets no son compatibles. Se trata de un mecanismo que permite al servidor enviar los datos al cliente de forma asíncrona una vez que se ha creado una tubería del servidor al cliente (creando un objeto llamado EventSource).
- Sondeo largo se utiliza, cuando tanto los WebSockets como los eventos enviados por el servidor no son compatibles. Se basa en el modelo de aplicación web Comet, en el que el cliente solicita información al servidor como en el sondeo normal, pero si el servidor no tiene información nueva para el cliente, en lugar de enviar una respuesta vacía, mantiene la solicitud abierta y espera a que se envíe la información. Una vez que la tiene, el servidor completa la solicitud enviando una respuesta al cliente. Normalmente, después de esto, el cliente vuelve a solicitar inmediatamente información al servidor, por lo que éste casi siempre tiene una solicitud disponible en espera.
Entre bastidores, SignalR elige automáticamente el mejor método que esté dentro de las capacidades del servidor y del cliente
En este artículo, utilizaremos ASP.NET Core SignalR y algunas personas pueden confundirse entre éste y ASP.NET SignalR, así que vamos a aclarar este punto. Hay dos implementaciones de SignalR:
- ASP.NET SignalR – representado por el paquete NuGet Microsoft.AspNet.SignalR y se ejecuta en aplicaciones que utilizan el .NET Framework y System.Web;
- ASP.NET Core SignalR forma parte de la plataforma ASP.NET Core que se ejecuta tanto en .NET Core como en .NET Framework y utiliza el paquete NuGet Microsoft.AspNetCore.App. No es compatible con los clientes o servidores de ASP.NET SignalR.
En general, ASP.NET Core SignalR mantiene muchos de los mismos conceptos y capacidades centrales que SignalR. Aquí están las principales diferencias entre ellos:
- Reconexiones automáticas. No son compatibles con ASP.NET Core SignalR. La aplicación cliente debe iniciar explícitamente una nueva conexión cuando la necesite. Cuando ASP.NET SignalR apareció por primera vez, la reconexión automática parecía ser una buena idea, pero se demostró que tenía errores y era ineficiente. Lo mismo ocurre con el almacenamiento en búfer de los mensajes no enviados por el servidor, depende del servidor: implementarlo o no.
- Diferencias en el cliente. El cliente ASP.NET Core SignalR está escrito en TypeScript. Se puede utilizar JavaScript o la biblioteca del cliente TypeScript sin hacer referencia obligatoria a jQuery. Además, han cambiado una forma de obtención: en las versiones anteriores, el cliente JavaScript se obtenía a través de un paquete NuGet en Visual Studio, pero ahora puede utilizar npm para obtener e instalar el paquete.
- Escalado. Ahora tienen una pequeña diferencia en el escalado desde que el servicio Azure SignalR comenzó a soportar ASP.NET. Básicamente, SignalR se envió con soporte incorporado para el escalamiento utilizando Redis y SQL Server. ASP.NET Core SignalR fue rediseñado con un modelo de escalado más sencillo y más extensible: soporta Redis y Azure SignalR Service.
- Soporte de protocolos. ASP.NET Core SignalR soporta JSON, un nuevo protocolo binario basado en MessagePack, y también permite crear protocolos personalizados.
- Inyección de dependencia (DI). ASP.NET Core se entrega con DI integrado en el marco. Los servicios pueden utilizarlo para acceder al HubContext (y revisaremos este punto más adelante en el artículo).
En este artículo, revisaremos el proceso de creación de un simple chat, aunque es un ejemplo muy “clásico”, es fácil mostrar el proceso general de trabajo con SignalR y no consume nada de tiempo. Como marco de trabajo para el frontend, utilizaremos Vue.js, un marco de trabajo de JavaScript de código abierto para la construcción de interfaces de usuario. Por el momento, ASP.NET Core sólo soporta Angular, React y React con Redux out-of-the-box. En el siguiente párrafo, repasaremos un poco cómo se puede manejar esta situación y le daremos una visión general de lo que vamos a trabajar en la parte práctica.
Dado que nuestro objetivo principal es conseguir algunos conocimientos sobre cómo trabajar con ASP.NET Core SignalR, no revisaremos Vue.js en detalle. Seguramente, proporcionaremos algunos detalles que permitirán a los lectores obtener una comprensión general de cómo funciona todo, pero no de forma excesivamente detallada.
ASP.NET Core con Vue.js
La discusión sobre qué sería mejor utilizar: ReactJS, Angular, Vue.js u otra cosa puede ser un tema digno de un artículo independiente. En este, hemos elegido el framework Vue.js ya que es bastante sencillo, pero potente y con una buena documentación (que también es algo importante, especialmente para los principiantes). Vue se convirtió en el proyecto de front-end más popular de GitHub en 2018, en el momento de escribir este artículo tiene 148 mil estrellas y más de 21 mil forks en GitHub. Además, Vue.js no tiene una plantilla oficial y aquellos que necesitan utilizarlo pueden estar un poco confundidos con lo que deben hacer. Todas estas razones han servido de impulso para elegir Vue.js y mostrar algunas de las soluciones disponibles para los lectores.
El problema de la falta de plantillas se produjo para los desarrolladores con la versión ASP.NET Core 2.1. Anteriormente, las plantillas de SPA estaban disponibles a través del paquete Microsoft.AspNetCore.SpaTemplates y tenían soporte para Vue.js. Desde que todas las plantillas SPA se trasladaron al repositorio del núcleo, su elección se volvió más limitada. La buena noticia es que hay algunas formas de resolver este problema
La primera variante es crear un proyecto separado para el frontend utilizando el Vue CLI. Esta es una solución muy común y puede encontrar muchos manuales para ello. Esta variante es también más complicada pero tiene sus propias ventajas, como el escalado independiente y la posibilidad de utilizar opciones de alojamiento adecuadas para cada uno.
El segundo enfoque consiste en sustituir React por Vue.js en la plantilla React SPA de forma manual. De hecho, así es precisamente como se crearon algunas plantillas de código abierto, por lo que ya puede entender su base y naturaleza.
En aras de la brevedad, no nos detendremos en todas estas soluciones. En su lugar, nos detendremos en la última solución de la lista: utilizar las plantillas ya creadas (que hemos mencionado anteriormente). Hay bastantes plantillas de código abierto que puede utilizar. Nosotros hemos elegido la bastante popular de TrilonIO. De hecho, puede probar cualquier otra plantilla y decidir cuál le conviene más. Nuestra elección se debe a que tenemos una buena experiencia utilizando esta plantilla en uno de nuestros proyectos
Ahora, cuando tenga una visión sobre para qué es adecuado SignalR, qué requisitos necesitamos para nuestra demostración y qué nos ha llevado a esa elección, podemos empezar a revisar todo el proceso de forma específica.
Cómo empezar con Vue.js y ASP.NET Core SignalR
Configuración del proyecto
En este apartado, repasamos el proceso de creación de un chat sencillo en detalle, por lo que aquellos que ya estén familiarizados de alguna manera con él pueden saltarse la explicación y limitarse a repasar la forma de trabajar con SignalR. Sin embargo, para los principiantes, debe ser útil e interesante ver el proceso desde cero. Revisamos una variante de la creación de una nueva solución junto con el proyecto utilizando Windows PowerShell. Debe haber instalado Node.js y .NET Core, y por supuesto tener algún IDE.
Entonces, comencemos. Abra la consola, navegue hasta su carpeta y ejecute el siguiente comando:
1 2 3 | $ dotnet new sln -n RealTimeApp |
Con el comando dotnet new
puede crear un nuevo proyecto, archivo de configuración o solución basado en la plantilla especificada con todas las dependencias necesarias. Aquí indicamos que queremos crear una solución (mediante la opción sln
) con el nombre RealTimeApp
(mediante la opción n RealTimeApp
). Si no especifica el nombre, éste corresponderá automáticamente al nombre de la carpeta. Después de ejecutar este comando, debería ver una solución recién creada en su carpeta. En relación con la estructura estándar del proyecto, cree una nueva carpeta cerca de la solución con el siguiente comando:
1 2 3 | $ md RealTimeAppCore |
Utilizamos además la plantilla TrilonIO, que debe instalarse manualmente ejecutando el siguiente comando dentro de la carpeta creada:
1 2 3 | $ dotnet new --install "aspnetcore-vuejs" |
Como resultado, debería ver una lista de todas las plantillas disponibles y debería poder crear un nuevo proyecto con cualquiera de ellas. La plantilla que necesitamos debe tener un nombre vuejs, y con el comando siguiente podemos crear un nuevo proyecto con ella:
1 2 3 | $ dotnet new vuejs |
El nombre del proyecto es el mismo que el nombre de la carpeta, lo cual es adecuado para nosotros. Los comandos anteriores sólo crean el nuevo proyecto y la solución, pero no están conectados entre sí. Para vincularlos, vuelva a la carpeta de la solución y ejecute este comando:
1 2 3 | $ dotnet sln add .RealTimeAppCoreRealTimeAppCore.csproj |
Si ahora abre el proyecto en el Visual Studio verá un proyecto bastante estándar con unos cuantos controladores, vistas y modelos, así como un ejemplo básico de uso. El modelo puede ser bastante interesante para aquellos, que no tienen experiencia con Vue.js. Creamos todo desde cero, así que vamos a eliminar los siguientes archivos innecesarios:
- …ClientAppcomponentesNsobre.vue
- …ClientAppcomponentsfetch-data.vue
- …ClientAppcomponentscounter-example.vue
- toda la carpeta…Nde proveedores
- …NControladoresNdel tiempo.cs
- …ModelosNPrevisión del tiempo.cs
Después de borrarlos puede encontrarse con algunos errores. Para solucionarlos, sólo tiene que limpiar la StartupClass eliminando las siguientes líneas:
- using RealTimeAppCore.Providers;
- services.AddSingleton();
En este punto, tenemos un proyecto limpio, así que podemos empezar a configurar un proyecto para nuestras necesidades. En primer lugar, necesitaremos un modelo y un controlador. Haga clic con el botón derecho del ratón en la carpeta “Modelos”, seleccione “Añadir” en el menú contextual y cree una nueva clase “Mensaje”. En nuestro caso debe contener sólo dos campos: “Texto” y “Fecha”, como se muestra a continuación:
1 2 3 4 5 6 7 8 9 10 11 | using System; namespace RealTimeAppCore.Models { public class Message { public string Text { get; set; } public DateTime Date { get; set; } } } |
La estructura es bastante simple, por eso no tenemos necesidad de revisarla. El controlador será un poco más complicado. Al igual que para los modelos, haga clic con el botón derecho del ratón en la carpeta “Controladores”, seleccione “Añadir” en el menú contextual y cree una nueva clase “MessagesController”. Este es el contenido de este archivo, que revisamos a continuación:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using Microsoft.AspNetCore.Mvc; using RealTimeAppCore.Models; using System.Collections.Generic; namespace RealTimeAppCore.Controllers { [Route("api/[controller]")] public class MessagesController : Controller { [HttpGet("[action]")] public IActionResult GetMessages() { List messages = new List(); var result = new { messages }; return Ok(result); } } } |
Con el atributo [Route("api/[controller]")]
establecemos que todos los métodos dentro de este controlador pueden ser ejecutados para la ruta [host]/api/[nombre del controlador]/[nombre del método]
. Los principiantes deben tener en cuenta que el nombre del controlador significa la parte del nombre sin la palabra ‘Controlador’, así que para el método GetMessages
la URL es [host]/api/Messages/GetMessages
. En este punto sólo tenemos un método, que devuelve una lista vacía de mensajes
Para terminar de configurar nuestro proyecto, también tenemos que hacer algunos cambios en los archivos del frontend. En primer lugar, vamos a limpiar nuestras rutas sustituyendo el contenido del archivo ClientApprouterroutes.js
por las siguientes líneas:
1 2 3 4 5 6 7 | import HomePage from 'components/home-page' export const routes = [ { name: 'home', path: '/', component: HomePage, display: 'Home', icon: 'home' } ] |
Sólo necesitamos un enrutamiento simple, por lo que el enrutamiento limpio (ya que eliminamos otras vistas) del ejemplo nos conviene. En segundo lugar, necesitamos actualizar nuestra página de inicio. En este paso, sólo eliminamos todos los datos innecesarios y añadimos un cargador simple, un título y un método para obtener los datos. Sustituya el contenido del archivo ClientAppcomponentshome-page.vue
por las siguientes líneas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <div> <h1>Simple chat</h1> <div class="text-center"> <p><em>Loading...</em></p> <h1></h1> </div> <div> <p><em>Message:</em> '{{ message.text }}'</p> </div> </div> export default { data() { return { messages: null } }, methods: { async loadMessages() { try { let response = await this.$http.get('/api/messages/getMessages') this.messages = response.data.messages } catch (err) { console.log(err) } } }, async created() { this.loadMessages() } } |
Para aquellos que no estén familiarizados con Vue.js, repasemos un poco el contenido de este archivo. Cuando se crea una instancia de Vue, añade todas las propiedades que se encuentran en su objeto de datos al sistema de reactividad de Vue. En nuestro ejemplo, acabamos de establecer que tenemos un objeto vacío “mensajes”, que se actualizará en el método loadMessages
.
Cada instancia de Vue al crearse pasa por una serie de pasos de inicialización y ejecuta las funciones llamadas “ganchosdel ciclo de vida“. Con la ayuda de estos ganchos, puede añadir su propio código para realizar en etapas específicas. En nuestro ejemplo, utilizamos el gancho “creado” para establecer el objeto de mensaje con los datos del controlador después de la creación de la instancia Vue.
De hecho, aquellos de los lectores, que sólo quieren saber cómo configurar un proyecto ASP.NET Core con Vue.js deben tener una plantilla básica ahora.
Configurar SignalR
Ahora es el momento de conocer el punto clave del artículo: SignalR. No necesita ninguna instalación adicional, ya que forma parte del metapaquete Microsoft.AspNetCore.App, que debe instalarse automáticamente.
Para habilitar SignalR sólo tiene que actualizar su clase de inicio de la siguiente manera:
- añada el uso del espacio de nombres
Microsoft.AspNetCore.SignalR;
en la parte superior del archivo; - actualice el método ConfigureServices añadiendo la llamada services.AddSignalR, que configura los servicios requeridos por el middleware SignalR:
1234567public void ConfigureServices(IServiceCollection services) {services.AddSignalR();// Add framework services.services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);} - configure las rutas SignalR llamando a app.UseSignalR en el método Startup.Configure:
12345678910111213141516171819202122232425262728293031323334public void Configure(IApplicationBuilder app, IHostingEnvironment env) {if (env.IsDevelopment()) {app.UseDeveloperExceptionPage();// Webpack initialization with hot-reload.app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {HotModuleReplacement = true,});} else {app.UseExceptionHandler("/Home/Error");// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.app.UseHsts();}app.UseHttpsRedirection();app.UseStaticFiles();app.UseSignalR(route => {route.MapHub("/signalr-hub");});app.UseMvc(routes => {routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");routes.MapSpaFallbackRoute(name: "spa-fallback",defaults: new { controller = "Home", action = "Index" });});}
Con una línea route.MapHub("/signalr-hub")
, configuramos la clase SignalRHub
como gestor de peticiones para la ruta “signalr-hub”, por lo que los clientes deberían poder conectarse con el hub en [host]/signalr-hub
Empezar con los Hubs de SignalR
Mediante los hubs, ASP.NET Core SignalR hace posible la comunicación bidireccional entre el servidor y el cliente. Como se describe en la documentación oficial, los hubs llaman al código del lado del cliente enviando mensajes que contienen el nombre y los parámetros del método del lado del cliente. El cliente intenta hacer coincidir el nombre con un método en el código del lado del cliente. Cuando se encuentra una coincidencia, llama al método y le pasa los datos de los parámetros deserializados.
La creación de Hubs es un proceso muy sencillo. Cree una nueva carpeta llamada “Hubs” dentro del proyecto y añada un nuevo archivo SignalRHub.cs
. Nuestra nueva clase debe heredar de la clase base Hub:
1 2 3 4 5 6 7 8 | using Microsoft.AspNetCore.SignalR; namespace ResPlanner.Hubs { public class SignalRHub : Hub { } } |
También puede añadir métodos públicos dentro de esta clase, que pueden ser llamados por los clientes. SignalR maneja la serialización y deserialización en parámetros y devuelve valores, por lo que puede especificarlos como en cualquier método de C#
También utilizamos la librería cliente de SignalR JavaScript para gestionar el establecimiento de la conexión con nuestro Hub y para gestionar los eventos. Se entrega como un paquete npm, por lo que puede instalarlo fácilmente ejecutando este comando:
1 2 3 | $ npm install --save-dev @aspnet/signalr |
Ahora, estamos listos para el último paso de la guía: vamos a crear un nuevo método en el controlador, que recibirá un nuevo mensaje, enviará un evento a todos los clientes, y preparará a nuestro cliente para recibir este evento.
Como necesitamos enviar un evento no desde el propio Hub, sino desde el controlador, tenemos que inyectar un IHubContext
en el controlador añadiéndolo al constructor, como puede ver en el listado de abajo. También añadimos un nuevo método, que recibe un modelo creado anteriormente y envía un evento a todos los clientes conectados, utilizando Clients.All
. Este es el aspecto que debe tener ahora su controlador:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using RealTimeAppCore.Models; using ResPlanner.Hubs; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace RealTimeAppCore.Controllers { [Route("api/[controller]")] public class MessagesController : Controller { /// <summary> /// The context /// </summary> private readonly IHubContext _hubContext; public MessagesController(IHubContext hubContext) { _hubContext = hubContext; } [HttpGet("[action]")] public IActionResult GetMessages() { List messages = new List(); var result = new { messages }; return Ok(result); } [HttpPost("[action]")] public async Task SendMessage([FromBody]Message message) { await _hubContext.Clients.All.SendAsync("RefreshEvent", Json(new { text = message.Text, date = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") })); } } } |
Básicamente, todos estos son cambios para el lado del servidor. Para conectar y escuchar los eventos del servidor, en el lado del cliente debemos hacer lo siguiente:
- dentro del método
initSignalR()
:- crear una nueva conexión con el Hub con las siguientes líneas:
12345678this.connection = new HubConnectionBuilder().withUrl(window.location.origin + '/signalr-hub').configureLogging(LogLevel.Information).build();…this.connectToSignalR(); - configurar la reconexión después de 5 segundos, si la conexión del Hub se cierra:
12345this.connection.onclose(() => {this.connectToSignalR();}) - empezar a escuchar el evento
RefreshEvent
del servidor. Una vez recibido, nuestra lista de mensajes debería actualizarse con nuevos datos:
123456this.connection.on('RefreshEvent', (data) => {this.messages.push({ text: data.value.text, date: data.value.date })this.$store.getters.needReloadPage})
- crear una nueva conexión con el Hub con las siguientes líneas:
- añadir el método
connectToSignalR
, en el que realmente establecemos una conexión:
123456789connectToSignalR() {this.connection.start().catch(err => {console.error('Failed to connect with hub', err)return new Promise((resolve, reject) =>setTimeout(() => this.connectToSignalR().then(resolve).catch(reject), 5000))})}
Además, debemos añadir un nuevo método para enviar un mensaje al servidor. Primero, añadimos algún formulario para la entrada del usuario después de la plantilla con un campo de entrada y un botón, así:
1 2 3 4 5 6 7 8 9 | <section class="form"> <div class="field"> <div class="control"> <button class="dark-bg text-white submit-button">Submit</button> </div> </div> </section> |
A continuación, vinculamos el valor del elemento de entrada del formulario a los datos de la instancia de Vue mediante la directiva v-model, de modo que los datos deberían tener este aspecto:
1 2 3 4 5 6 7 8 9 10 | data() { return { messages: [], form: { textMessage: '' } } }, |
Por último, añadimos el método sendMessage()
, que debe ser llamado después de que el usuario haga clic en el botón y que debe llamar al método SendMessage
del controlador. Así, después de todos estos cambios, su archivo home-page.vue
debería contener lo siguiente
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | <div> <h1>Simple chat</h1> <div class="text-center"> <p><em>Loading...</em></p> <h1></h1> </div> <div> <p><em>Message at {{ message.date }}:</em> '{{ message.text }}'</p> </div> <section class="form"> <div class="field"> <div class="control"> <button class="dark-bg text-white submit-button">Submit</button> </div> </div> </section> </div> import { HubConnectionBuilder, LogLevel } from '@aspnet/signalr' export default { data() { return { messages: [], form: { textMessage: '' } } }, methods: { async loadMessages() { try { let response = await this.$http.get('/api/messages/getMessages') console.log(response.data.messages) this.messages = response.data.messages } catch (err) { window.alert(err) console.log(err) } }, initSignalR() { this.connection = new HubConnectionBuilder() .withUrl(window.location.origin + '/signalr-hub') .configureLogging(LogLevel.Information) .build(); this.connection.onclose(() => { this.connectToSignalR(); }) this.connectToSignalR(); this.connection.on('RefreshEvent', (data) => { this.messages.push({ text: data.value.text, date: data.value.date }) this.$store.getters.needReloadPage }) }, connectToSignalR() { this.connection.start().catch(err => { console.error('Failed to connect with hub', err) return new Promise((resolve, reject) => setTimeout(() => this.connectToSignalR().then(resolve).catch(reject), 5000)) }) }, closeConnectionSR() { if (!this.connection) return; this.connection.off('RefreshEvent'); this.connection = null; }, sendMessage() { this.$http.post('api/Messages/SendMessage', { text: this.form.textMessage }) .then(request => { console.log(request) if (request.status = 200) { this.form.textMessage = ''; } }); } }, async created() { this.initSignalR() } } |
¡Ahora puede empezar a probar nuestro chat de demostración! Intente abrir dos ventanas de navegador diferentes y comience a chatear – verá que todos los clientes disponibles mostrarán los datos actualizados:
Conclusión
En este artículo, hemos intentado cubrir todos los aspectos generales de cómo empezar a trabajar con ASP.NET Core, Vue.js y SignalR. Aquí también puede encontrar algunos detalles sobre qué es SignalR, qué beneficios proporciona, una breve comparación de ASP.NET SignalR y ASP.NET Core SignalR, etc. Esperamos que este artículo haya disipado algunos temores de los principiantes, y haya mostrado otra forma de trabajar con estas tecnologías para los desarrolladores más experimentados. Por lo tanto, creemos que todo el mundo debería ser capaz de encontrar algo interesante y nuevo aquí