Artículos relacionados
Introducción
En el post anterior se terminó de desarrollar la presentación que va a tener la UI del panel de comentarios desarrollada con ReactJs. En este post veremos la integración con MVC y SignalR. En la parte de MVC veremos cómo crear Actions para devolver y registrar datos, por el momento en memoria. Por el lado de SignalR veremos cómo crear una clase Hub para notificar a todos los clientes cada vez que alguien agregue un nuevo comentario.
Configuración SignalR
Vamos al Administrador de paquetes de Nuget y agregamos la referencia de los paquetes Microsoft.Owin y Microsoft.AspNet.SignalR al proyecto web.
Agregamos una clase llamada Startup, dentro de la carpeta App_Start, que se encarga de configurar el uso de SignalR en el sitio web y copiamos el siguiente código.
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(PanelComentario.Startup))] namespace PanelComentario { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
SignalR Hub
En la raíz de proyecto creamos una carpeta llamada Hubs y dentro una clase llamada CommentarioHub con el siguiente código:
using Microsoft.AspNet.SignalR; namespace PanelComentario.Hubs { public class ComentarioHub : Hub { } }
Esta clase será la encargada de devolver la respuesta desde el servidor a la UI cada vez que se agregue un nuevo comentario.
MVC
En la carpeta Models agregamos una clase llamada ComentarioModel y agregamos el siguiente código:
namespace PanelComentario.Models { public class ComentarioModel { public string Identificador { get; set; } public string FechaHora { get; set; } public string Autor { get; set; } public string Texto { get; set; } } }
De nuevo en la carpeta Models agregamos una clase llamada RepositorioInMemoryComentario encargada de manejar los datos en memoria, a esta clase le agregamos el siguiente código:
using System.Collections.Generic; using System.Linq; namespace PanelComentario.Models { public static class RepositorioInMemoryComentario { private static readonly IList<ComentarioModel> comentarios; static RepositorioInMemoryComentario() { comentarios = new List<ComentarioModel> { new ComentarioModel { Autor = "Scrumcito", Texto = "Apliquemos scrum a todo", FechaHora="11/11/2011 11:11:11", Identificador="4321" }, new ComentarioModel { Autor = "ArquitectoPpt", Texto = "Todo esta en la ppt", FechaHora="12/12/2012 12:12:12", Identificador="1234" } }; } public static void Agregar(ComentarioModel comentario) { comentarios.Add(comentario); } public static IList<ComentarioModel> TraerTodo() { return comentarios.Reverse().ToList(); } } }
En la controladora PanelController agregamos el siguiente método para devolver todos los comentarios:
[OutputCache(Location = OutputCacheLocation.None)] public ActionResult Comentarios() { return Json(RepositorioInMemoryComentario.TraerTodo(), JsonRequestBehavior.AllowGet); }
Ahora agregamos el método encargado de registrar los comentarios en la controladora PanelController:
[HttpPost] public ActionResult Comentario(ComentarioModel comentario) { comentario.Identificador = Guid.NewGuid().ToString(); RepositorioInMemoryComentario.Agregar(comentario); NotificarComentarioNuevo(); return Content(comentario.Identificador); }
Para notificar a todos los clientes cuando se agregue un nuevo comentario agregamos el siguiente método:
private static void NotificarComentarioNuevo() { // Recupera el contexto del Hub comentario, este contiene la referencia // de todos los clientes que se han conectado var hubContext = GlobalHost.ConnectionManager.GetHubContext<ComentarioHub>(); // Notifica a todos los clientes llamando al método agregarComentario // y devuelve todos los comentarios registrados, el metodo se encuentra // en el archivo PanelComentario.jsx hubContext.Clients.All .agregarComentario(RepositorioInMemoryComentario.TraerTodo()); }
Finalmente, vamos a la vista Panel/Index.cshtml y agregamos los siguientes scripts debajo de la llamada de jQuery para hacer las llamadas al Hub de Comentarios en SignalR:
<script src="~/scripts/jquery-2.2.0.js"></script> <!-- Cambio --> <script src="~/scripts/jquery.signalR-2.2.0.js"></script> <script src="~/signalr/hubs"></script> <!-- Cambio --> <script src="https://fb.me/react-0.14.0.js"></script>
React JS
Abrimos el archivo Scripts/App/RegistroComentario.jsx y modificamos el contenido de la función submitComentario por el siguiente código:
submitComentario: function (e) { e.preventDefault(); // this.refs : es un identificador que sirve para buscar elementos var autor = this.refs.autor.value.trim(); var texto = this.refs.texto.value.trim(); if (!texto || !autor) { return; } this.props.enviarComentario({ Autor: autor, Texto: texto }); this.refs.autor.value = ''; this.refs.texto.value = ''; return; }
Nota: Para más información acerca de atributo refs recomiendo leer el siguiente enlace.
Ahora modificamos el script PanelComentario.jsx con el siguiente código:
"use strict" var PanelComentario = React.createClass({ cargarComentariosAPI: function () { var xhr = new XMLHttpRequest(); xhr.open('get', this.props.cargarComentariosUrl, true); xhr.onload = function () { var data = JSON.parse(xhr.responseText); this.setState({ comentarios: data }); }.bind(this); xhr.send(); }, enviarComentarioAPI: function (comentario) { var comentarios = this.state.comentarios; comentarios.unshift(comentario); this.setState({ comentarios: comentarios }); var data = new FormData(); data.append('Autor', comentario.Autor); data.append('Texto', comentario.Texto); var xhr = new XMLHttpRequest(); xhr.open('post', this.props.envioComentarioUrl, true); xhr.send(data); }, comentarioAgregadoAPI: function (comentarios) { this.setState({ comentarios: comentarios }); }, getInitialState: function () { return { comentarios: [] }; }, componentWillMount: function () { this.cargarComentariosAPI(); }, componentDidMount: function () { // Registro del cliente al Hub Comentario de SignalR // Acá se define la función de JS que se debe invocar // cuando se llame al método agregarComentario desde el servidor var comentarioHub = $.connection.comentarioHub; $.connection.hub.start(); comentarioHub.client.agregarComentario = this.comentarioAgregadoAPI }, render: function () { return ( <div className="panelComentarios"> <h1>Panel de comentarios</h1> <RegistroComentario enviarComentario={this.enviarComentarioAPI}/> <ListaComentario comentarios={this.state.comentarios} /></div> ); } });
NOTA: Para más detalle sobre los métodos componentDidMount, componentWillMount, getInitialState y render los invito a leer este artículo.
Para terminar con los componentes de ReactJs abrimos el script Main.jsx y copiamos el siguiente código:
"use strict"; ReactDOM.render( <PanelComentario envioComentarioUrl="/panel/comentario" cargarComentariosUrl="/panel/comentarios" /> , document.getElementById("contenido"));
Ahora para ver que todo esté bien compilamos la solución, presionamos f5 y navegamos a la url Panel/Index y debemos ver el panel de comentarios en pantalla.
El código puede ser descargado desde este enlace.
Referencias:
- ReactJS – Component Specs and Lifecycle
- ReactJs .Net Tutorial
- Pluralsight – Building Applications with React and Flux
Metal Tip:
Este artículo lo escribí escuchando la canción War Pigs de la banda Black Sabbath de Inglaterra, les comparto el enlace.
Happy coding and Stay Heavy lml