Sistemas hipermedia en ASP.NET MVC 5. Primera parte: el comienzo / Sudo Null IT News
El comienzo de un artículo sobre el desarrollo rápido de una aplicación web centrada en hipermedia con HTMX 2.0.
Introducción
Les presento mi primer tutorial sobre el desarrollo de aplicaciones hipermedia. En este artículo me referiré simplemente a ellas como aplicaciones hipermedia. Mi artículo trata sobre el desarrollo de una aplicación interactiva moderna utilizando la biblioteca Htmx.js en una plataforma heredada.
Usaremos la plataforma de servidor ASP.NET MVC 5 heredada. Se lanzó en 2013 y, aunque hace tiempo que se suspendió, muchos proyectos más antiguos creados en esta plataforma cuentan con el respaldo de los desarrolladores y aún funcionan muy bien. El problema surge cuando es necesario modernizar, adaptar e interactuar un sitio o una aplicación tan antigua. Aquí es donde pertenecen los sistemas hipermedia. No hay necesidad de estropear la hermosa arquitectura monolítica de las aplicaciones web antiguas agregando marcos de interfaz de usuario. Esto es una pérdida de tiempo y esfuerzo. Con la ayuda de los sistemas hipermedia, puede darle nueva vida fácilmente a su antigua aplicación.
Tengo experiencia limitada en la modernización exitosa de una aplicación web antigua y de gran tamaño introduciendo en ella sistemas hipermedia. Como resultado, la aplicación heredada comenzó a funcionar y a parecerse a una aplicación moderna. Al mismo tiempo, se ahorró una cantidad significativa de esfuerzo y tiempo. Nunca he usado ningún marco de front-end porque era innecesario. Les pido comprensión y no ser demasiado críticos con mi artículo. Este es mi primer artículo en este formato. Creo que mi poca experiencia en la modernización de una aplicación antigua puede resultar de gran utilidad para algunos desarrolladores que trabajan con aplicaciones web antiguas. Además, en las nuevas versiones de la plataforma del servidor ASP.NET Core, trabajar con sistemas hipermedia es mucho más fácil y conveniente.
Las técnicas para trabajar con sistemas hipermedia se mostrarán, por supuesto, no utilizando código de producción, sino utilizando el ejemplo de un juego de mesa sencillo. Usar un juego de mesa como ejemplo hará que tu introducción al hipermedia sea fácil y divertida. Aunque la aplicación pueda parecer voluminosa, mis ejemplos serán detallados, simplificados al máximo y acompañados de explicaciones. Puede comprenderlos fácilmente y luego utilizarlos en sus aplicaciones.
Audiencia
Este artículo está destinado principalmente a desarrolladores que quieran familiarizarse con los sistemas hipermedia HTMX. En primer lugar, se requiere conocimiento del lenguaje de programación C#; no se requiere conocimiento de la plataforma de desarrollo ASP.NET de ninguna versión, pero es bienvenido.
Después de leer este artículo y trabajar con varios ejemplos, se familiarizará con la tecnología para desarrollar aplicaciones interactivas modernas: hipermedia. Dominarás y aprenderás a crear elementos hipermedia básicos. Y debido a que el artículo utiliza una plataforma obsoleta, puede aplicar fácilmente el conocimiento adquirido en sus antiguos proyectos heredados.
Sistemas hipermedia
Para empezar, en este artículo daré una definición de sistemas hipermedia a partir de la fuente original, del libro de Carson Gross.
Definimos un sistema hipermedia como un sistema que sigue una arquitectura de red RESTful tal como la entendió originalmente Roy Fielding.
~ Carson Gross Desarrollo de hipermedia. Htmx e hipervista
Roy Fielding Roy Thomas Fielding es un ingeniero estadounidense, uno de los principales autores de la especificación HTTP y fundador del estilo arquitectónico Representational State Transfer (REST).
Carson Gross es el desarrollador de la biblioteca htmx.js y autor del libro sobre sistemas hipermedia “Hypermedia Development. Htmx e Hipervista”.
Es esta maravillosa definición en la que nos basaremos en este artículo. Entonces, el hipertexto es texto generado usando lenguaje de marcado (por ejemplo, HTML) con vistas a utilizar hipervínculos. Hipermedia es el desarrollo lógico y técnico del hipertexto. Hipermedia es hipertexto que incorpora gráficos, sonido, video, datos y enlaces para crear una colección de entornos de información no lineales.
En general, un sistema hipermedia es una combinación de un elemento hipermedia en una página web, un código de servidor para soportar este elemento hipermedia y comunicación de red entre ellos.
Veamos esto con ejemplos. Tomemos una etiqueta de anclaje simple incrustada en un documento HTML más grande. Este elemento es un hipervínculo a otro documento.
Listado: Hipervínculo simple
<a href="
Яндекс
</a>
Este es un ejemplo de un elemento hipermedia simple que el navegador reconoce y procesa. El navegador se puede llamar cliente hipermedia y el servidor se puede llamar servidor hipermedia. A continuación, veamos cómo implementar un botón hipermedia simple basado en HTML utilizando la biblioteca Htmx.js.
Este es un ejemplo de un elemento hipermedia simple que el navegador reconoce y procesa. El navegador se puede llamar cliente hipermedia y el servidor se puede llamar servidor hipermedia. A continuación, veamos cómo implementar un botón hipermedia simple basado en HTML utilizando la biblioteca Htmx.js.
Listado: Botón hipermedia simple
<button hx-get="/counter" hx-target="#counter">
Прочитать счетчик
</button>
Este botón basado en Htmx.js intercambia hipermedia con el servidor de la misma manera que un hipervínculo. La biblioteca Htmx.js agrega funcionalidad a la etiqueta
Por supuesto, existen otras bibliotecas similares a Htmx.js. Sí, ha habido otros intentos fallidos de revivir HTML de diversas maneras. Pero sólo ahora esta biblioteca ofrece una opción exitosa para el desarrollo de hipermedia y se está volviendo cada vez más popular.
Crear una aplicación de prueba
Primero, creemos una aplicación hipermedia de muestra en el entorno de desarrollo Visual Studio 2022. No entraré en detalles sobre el proceso de instalación de este entorno de desarrollo, el kit de desarrollo o el proceso de creación de un proyecto. Esta información se puede encontrar disponible gratuitamente en Internet y el material del artículo se centra principalmente en trabajar con aplicaciones hipermedia. Simplemente crearemos una aplicación de muestra con un botón hipermedia para presentarle los sistemas hipermedia.
Primero, creemos un nuevo proyecto en el entorno de desarrollo de Visual Studio 2022. Seleccione el elemento de menú “Nuevo” en el menú principal “Archivo” y luego el subelemento “Proyecto…”. Se abrirá la ventana Crear proyecto. Filtre la lista de proyectos por “C#”, “Windows” y “Web” y seleccione el tipo de proyecto “Aplicación web ASP.NET (.NET Framework)” de la lista de proyectos.
Asigne a su nuevo proyecto y solución el nombre HelloHypermedia y seleccione .NET Framework 4.8. Haga clic en el botón “Siguiente” para continuar.
Es posible que no pueda encontrar un proyecto .NET Framework heredado en la lista de opciones disponibles para su selección. Luego, debe instalar adicionalmente el componente Proyecto .NET Framework y Plantillas de elementos en el Instalador de Visual Studio.
En la página siguiente, seleccione la plantilla “MVC”, deje los demás parámetros sin cambios y haga clic en el botón “Crear”.
El entorno de desarrollo creará un nuevo proyecto para nosotros, lleno de muestras iniciales. No eliminaremos las muestras iniciales en este ejemplo. Nos centramos principalmente en presentar el primer sistema hipermedia.
Agregaremos el primer elemento hipermedia a la página principal de la aplicación. Busque el archivo Index.cshtml en la carpeta Ver y en la subcarpeta Inicio y reemplace su contenido con el contenido inicial de la siguiente lista.
Listado: Representación visual Vistas/Inicio/Index.cshtml
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Введение в гипермедиа</title>
</head>
<body>
Пустая страница
</body>
</html>
Hemos cambiado la página de inicio de la aplicación para mostrar simplemente el título. Por ahora es sólo una página en blanco.
Primer sistema hipermedia
Utilizando el sistema hipermedia, podemos solicitar datos de forma interactiva al responsable del tratamiento y actualizar la página mostrada en el navegador. Agreguemos el primer sistema hipermedia que mostrará un mensaje de bienvenida en la página.
Primero, necesitamos agregar la importación de la biblioteca Htmx.js a la representación visual de la página. Entonces necesitas agregar un sistema hipermedia. Cambie el archivo de presentación visual Index.cshtml para que se parezca a la siguiente lista. En la lista, los comentarios resaltan los bloques que deben agregarse.
Listado: Representación visual de Views/Home/Index.cshtml con botón hipermedia
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Введение в гипермедиа</title>
<script src=" // добавить
</head>
<body>
<h1>Первое гипермедийное приложение</h1> // заменить
<button hx-get="/home/hello"> // добавить
Привет
</button>
</body>
</html>
esta linea Estamos agregando la biblioteca de soporte de sistemas hipermedia Htmx desde el servidor unpkg.com a la representación visual.
A continuación agregamos un botón del sistema hipermedia que realizará una solicitud GET a la dirección especificada e insertará el resultado de la solicitud.
Debe agregar un nuevo método hipermedia Hello al controlador de inicio, que debería devolver un mensaje y la hora actual como resultado. Abra el archivo HomeController.cs en la carpeta Controladores y realice cambios como se muestra en la siguiente lista. Elimine los métodos innecesarios y agregue uno nuevo llamado Hello() en su lugar.
Listado: Clase HomeController con método de sistema hipermedia
using System.Web.Mvc;
namespace HelloHypermedia.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public string Hello() // Удалить другие и добавить этот метод
{
return "Привет, гипермедиа!";
}
}
}
Este método devuelve una cadena de texto con un mensaje de bienvenida como resultado de la ejecución. Cuando hace clic en el botón, esta cadena se mostrará dentro del botón. El texto del botón será reemplazado.
Ejecute la aplicación y haga clic en el botón. Debería ver el resultado que se muestra en las siguientes capturas de pantalla. En la parte superior está la página antes de presionar el botón y en la parte inferior está la página después de presionar el botón.
En todas partes hay un botón en la representación visual, un método de acción en el controlador y un medio de comunicación entre ellos: este es un sistema hipermedia. Después de esta exitosa introducción a los sistemas hipermedia, puede pasar a crear una aplicación web.
Aplicación hipermedia
Mi objetivo es demostrar la hipermedia en acción, por lo que omito algunos detalles que no se tratarán en detalle en este artículo.
Entonces, en este artículo, como anuncié anteriormente, crearemos un juego de mesa en línea “Espía”. Nuestro juego asignará aleatoriamente roles de jugador: pacífico o espía. Nos referimos a que los jugadores se sentarán en círculo en la misma mesa e interactuarán con el juego a través de una aplicación web abierta en los navegadores de sus teléfonos. Dado que estos juegos no requieren una interfaz de usuario sofisticada, los sistemas hipermedia son perfectos para este tipo de aplicaciones.
Plan
Se requieren las siguientes características de nuestro juego de mesa:
La página principal, donde se muestra la bienvenida al juego de mesa y el formulario de registro del juego;
Página de espera para todos los jugadores que participan en el juego con un botón para iniciar el juego;
Página del juego con información sobre tus roles en el juego y un formulario para votar por un espía;
Páginas que muestran resultados de juegos: victorias o derrotas.
En las siguientes secciones de este capítulo, crearemos un nuevo proyecto de juego de mesa, lo configuraremos y lo desarrollaremos gradualmente agregando nuevas características del juego.
Proyecto
Cree un nuevo proyecto en el entorno de desarrollo de Visual Studio 2022 similar al ejemplo anterior, pero ingrese el nombre del proyecto SpyOnlineGame. Seleccione también el tipo “Aplicación web ASP.NET (.NET Framework)” de la lista de proyectos y haga todo de la misma manera. Después de que el entorno de desarrollo vuelva a crear un nuevo proyecto para nosotros con muestras iniciales, podemos proceder directamente a crear una aplicación web.
En este artículo usaremos solo proyectos llenos de muestras iniciales para reducir el volumen del artículo y simplificar el ejemplo.
Preparación del proyecto
Abra la configuración web del proyecto. Haga clic derecho en el proyecto – “Propiedades” – pestaña “Web”. Cambie la página de inicio y configure el puerto en 44300 como se muestra en la siguiente captura de pantalla.
Hemos configurado la página de inicio, la dirección y el puerto en el que se iniciará nuestra aplicación web en modo depuración.
Abra el proyecto y reemplace el contenido del archivo del controlador doméstico con el contenido que se muestra en la siguiente lista. Elimine los métodos de acción no utilizados y deje solo el método de acción de índice inicial. Deje que se muestre la representación visual predeterminada cuando se inicia inicialmente la aplicación.
Listado: Reemplazo del contenido del archivo HomeController.cs
using System.Web.Mvc;
namespace SpyOnlineGame.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
Necesitamos reemplazar el contenido predeterminado de esta representación visual. La siguiente lista muestra el contenido del archivo Index.cshtml en la carpeta Vistas/Inicio. Es necesario llevar este archivo al formulario que se presenta en el siguiente listado. Deje que muestre solo información de bienvenida estilizada sobre el juego por ahora.
Listado: Nuevo contenido visual Index.cshtml
@{
ViewBag.Title = "Главная";
}
<div class="my-4 p-5 bg-danger text-light rounded">
<h1 class="text-center">Игра "Шпион"</h1>
<p>
Онлайн версия настольной игры "Шпион"
</p>
</div>
Además, elimine las representaciones visuales innecesarias en las carpetas Views/Home About.cshtml, Contact.cshtml y Views/Shared Error.cshtml.
En este artículo aprovecharemos al máximo la plantilla inicial. Por lo tanto, solo editaremos ligeramente los archivos de muestra iniciales del proyecto inicial. Edite la plantilla inicial Views/Shared/_Layout.cshtml. Esta plantilla será utilizada por todas las representaciones visuales de nuestra aplicación. Modifique esta plantilla para que se parezca a la siguiente lista.
Listado: Plantilla modificada _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Настольная игра "Шпион"</title> // Добавить
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<header> // Заменить
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark
bg-danger"> // Изменить
<div class="container">
@Html.ActionLink("Настольная игра \"Шпион\"", "Index", "Home",
null, new { @class = "navbar-brand" }) // Изменить
<button type="button"
class="navbar-toggler" data-bs-toggle="collapse"
data-bs-target=".navbar-collapse" title="Переключить навигацию"
aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse d-sm-inline-flex
justify-content-between">
</div>
</div>
</nav>
</header>
<div class="container"> // Добавить
<main role="main" class="pb-5 pt-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer bg-danger text-light"> // Заменить
<div class="container py-3">
<p>© @DateTime.Now.Year - Настольная игра "Шпион"</p>
</div>
</footer>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
Los comentarios marcan las líneas donde es necesario realizar cambios. En este artículo utilizaremos inmediatamente representaciones visuales estilizadas para reducir la extensión del artículo.
Finalmente, reemplace el contenido del archivo CSS Content/Site.css para darle estilo a nuestro juego de mesa en línea de una manera única.
Listado: Hoja de estilo en cascada modificada Site.css
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 80px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
}
.validation-summary-errors {
font-weight: bold;
color: #f00;
}
.input-validation-error {
border: 1px solid #f00;
background-color: #fee;
}
Después de iniciar la aplicación, se abrirá una ventana del navegador y se mostrará la página principal con información de bienvenida sobre nuestro juego de mesa en línea “Spy”. La siguiente captura de pantalla muestra la página de inicio de una aplicación que se ejecuta en modo de depuración.
Página de reglas del juego
Los participantes en el juego probablemente querrán leer las reglas del juego. Crearemos una página separada en la que mostraremos las reglas del juego.
Agreguemos un método de acción más al controlador, cuyo propósito es mostrar las reglas del juego. Agregue el método de acción adicional que se muestra en el listado a continuación.
Listado: Controlador principal complementado con un método más
using Microsoft.AspNetCore.Mvc;
namespace SpyOnlineGame.Controllers;
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Rules() // Добавить
{
return View();
}
}
Agreguemos una nueva representación visual para mostrar las reglas del juego. Agregue un objeto visual llamado Rules.cshtml a su carpeta Vistas/Inicio.
Haga clic derecho en la carpeta Vistas/Inicio y seleccione “Agregar” – “Ver” en el menú que aparece. En la ventana que se abre, seleccione “Vista MVC 5” y haga clic en el botón “Agregar”. Y en la ventana “Agregar vista”, ingrese solo el nuevo nombre de la vista visual: Reglas, como se muestra en la siguiente captura de pantalla. Después de hacer clic en el botón Agregar, se creará una nueva representación visual.
Complete esta representación visual con las reglas del juego, como se muestra en la siguiente lista.
Listado: Contenido de la representación visual con reglas Rules.cshtml
@{
ViewBag.Title = "Правила игры";
}
<h4>Правила</h4>
<p>Среди нескольких игроков затаился случайно выбранный 1 шпион.</p>
<p>Загадано одно случайное место, про которое не знает шпион, но знают мирные игроки.</p>
<p>Сначала один случайный игрок задает вопрос про место другому любому игроку про это место так, чтобы не догадался шпион. Потом тот - следующему любому и так по кругу.</p>
<p>Цель вопросов - определить кто шпион, при этом не выдать загаданное место, так как шпион про него ничего не знает. Ответы на вопросы должны показать, что вы не шпион, при этом вы не должны выдать загаданное место шпиону.</p>
<p>Есть несколько попыток угадать кто шпион. Если мирные не угадают, то побеждает шпион.</p>
<h5 class="mt-2">Варианты мест:</h5>
<ol class="list-group list-group-numbered">
<li class="list-group-item">Банк</li>
<li class="list-group-item">Казино</li>
<li class="list-group-item">Больница</li>
<li class="list-group-item">Офис</li>
<li class="list-group-item">Казино</li>
</ol>
<h5 class="mt-2">Примеры вопросов:</h5>
<ol class="list-group list-group-numbered">
<li class="list-group-item">Хорошо ли там кормят?</li>
<li class="list-group-item">Тяжело ли туда попасть?</li>
<li class="list-group-item">Ты рад был бы туда попасть?</li>
</ol>
Para que los participantes se familiaricen con estas reglas, cambiaremos el elemento del menú principal para que ahora enlace con la página de reglas del juego.
Listado: Plantilla de página Views/Shared/_Layout.cshtml con un nuevo elemento de menú
…
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm
navbar-dark bg-danger">
<div class="container">
@Html.ActionLink("Настольная игра \"Шпион\"", "Index", "Home",
null, new { @class = "navbar-brand" })
<button type="button" class="navbar-toggler"
data-bs-toggle="collapse" data-bs-target=".navbar-collapse"
title="Переключить навигацию"
aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse d-sm-inline-flex
justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li>@Html.ActionLink("Правила", "Rules", "Home", null,
new { @class = "nav-link" })</li> // Добавить
</ul>
</div>
</div>
</nav>
</header>
…
Y agregaremos un botón para ir a la página con las reglas del juego en la página principal del juego.
Listado: Página de inicio Vistas/Inicio/Index.cshtml con un botón
…
<div class="my-4 p-5 bg-danger text-light rounded">
<h1 class="text-center">Игра "Шпион"</h1>
<p>
Онлайн версия настольной игры "Шпион"
</p>
@Html.ActionLink("Правила игры", "Rules", null,
new { @class ="btn btn-primary mt-2"}) // Добавить
</div>
…
Por motivos de brevedad, no se muestra el resto del código. A continuación, en la captura de pantalla, puede ver cuál debería ser el resultado al ejecutar la aplicación en modo de depuración.
A continuación, debemos agregar un formulario de registro para los participantes del juego a la página principal. Comencemos agregando un modelo de datos.
Modelo de datos
En MVC, M significa modelo y es la parte más importante de una aplicación MVC. La carpeta Modelos se llenará con modelos de aplicaciones web. El modelo, a menudo denominado modelo de dominio, contiene los objetos C# (conocidos como objetos de dominio) que forman el núcleo de nuestra aplicación y los métodos que nos permiten manipularlos. Esta es la parte más importante de cualquier aplicación web.
No necesitamos un modelo de dominio complejo para el juego de mesa en línea SpyOnlineGame. Crearemos solo algunos modelos de nuestra aplicación que permitirán a los usuarios registrarse en un juego, esperar a que otros participantes se registren y luego jugar.
Según la convención MVC, las clases que componen el modelo se colocan en la carpeta Modelos. Haga clic con el botón derecho en Modelos en la ventana del Explorador de soluciones y seleccione Agregar seguido de Clase… en el menú emergente. Asigne al archivo el nombre Player.cs y haga clic en el botón Agregar para crear la clase. Cambie el contenido de esta clase para que coincida con el contenido del listado siguiente.
Listado: Contenido del modelo de reproductor
namespace SpyOnlineGame.Models
{
public class Player
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Este modelo almacenará información sobre cada participante registrado en el juego. Los usuarios podrán registrarse en el formulario de registro en la página principal de la aplicación.
Formulario de entrada de datos
Para el formulario de registro de los participantes del juego, crearemos un modelo web separado para registrar a los participantes. Crea una nueva carpeta “Web”. Esta carpeta contendrá todos los modelos y servicios web. En esta carpeta, cree otra carpeta llamada “Modelos”. Y agregue una nueva clase RegistrationWebModel a esta carpeta. Esta clase es un modelo de representación visual web normal que realiza la función de recibir datos del formulario. Complete esta clase con el contenido del siguiente listado.
Listado: Contenidos del modelo web RegistrationWebModel
using System.ComponentModel.DataAnnotations;
using SpyOnlineGame.Models;
namespace SpyOnlineGame.Web.Models
{
public class RegistrationWebModel
{
(Display(Name = "Ваше имя:"))
public string Name { get; set; }
public Player Map()
{
return new Player
{
Name = Name,
};
}
}
}
Ahora agreguemos un formulario de entrada de datos a la página principal Index.cshtml. Antes de hacer esto, agregue la importación del espacio de nombres del modelo web al archivo de configuración Views/Web.config, como se muestra en la siguiente lista.
Listado: Cambios en el archivo de configuración Web.config
…
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
…
<add namespace="SpyOnlineGame" />
<add namespace="SpyOnlineGame.Models" /> // Добавить
<add namespace="SpyOnlineGame.Web.Models" /> // Добавить
</namespaces>
</pages>
</system.web.webPages.razor>
…
Agregue contenido nuevo a este archivo de representación de la página de inicio, que se muestra en la lista a continuación.
Listado: Formulario de ingreso de datos en la página principal Index.cshtml
@model RegistrationWebModel
@{
ViewBag.Title = "Главная";
}
<div class="my-4 p-5 bg-danger rounded">
<h1 class="text-center">Игра "Шпион"</h1>
<p>
Онлайн версия настольной игры "Шпион"
</p>
<a asp-action="Rules" class="btn btn-dark">Правила игры</a>
</div>
<div class="p-2 bg-light border rounded"> // Добавить весь блок
@using (Html.BeginForm("Registration", "Home", FormMethod.Post))
{
<h5>Регистрация нового участника игры</h5>
<div class=”form-group”>
@Html.LabelFor(m => m.Name, new { @class="form-label" })
@Html.TextBoxFor(m => m.Name, new { @class="form-control" })
</div class=”my-2”>
<input class="btn btn-primary" type="submit"
value="Зарегистрироваться" />
}
</div>
La expresión @model en la parte superior de la página especifica el tipo de objeto que este objeto visual obtiene del método de acción del controlador. Describimos la etiqueta y los elementos de entrada para la propiedad Nombre del modelo web para registrar un nuevo participante en el juego usando los métodos auxiliares LabelFor() y TextBoxFor().
El método BeginForm() establece el dibujo del formulario de entrada de datos y los parámetros de este método establecen la configuración del formulario. Ahora se procesará para enviar los datos del formulario al método de acción de Registro con una solicitud POST. Todavía no existe tal método de acción; es necesario agregarlo al controlador.
Recuperar datos de un formulario
Después de hacer clic en el botón Enviar (este es un elemento de entrada con un atributo de tipo enviar), el navegador recopilará datos del formulario y los enviará al servidor. Agregue un método para recuperar datos de registro de usuario desde el formulario de la página principal de la aplicación mediante una solicitud POST. La siguiente lista muestra el código para el método Registro() que debe agregarse al controlador de inicio.
Listado: Nuevo método de acción para recibir datos de un formulario en un controlador
using System.Web.Mvc;
using SpyOnlineGame.Web.Models; // Добавить
namespace SpyOnlineGame.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
(HttpPost) // Добавить
public ActionResult Registration(RegistrationWebModel model) // Добавить
{
return View("Index");
}
public ActionResult Rules()
{
return View();
}
}
}
Hemos agregado el atributo HttpPost a este método para indicar que este método solo procesa solicitudes POST entrantes. Este método de acción debería guardar los detalles del nuevo participante en el juego y redirigir a la página de espera para todos los jugadores.
Cree una nueva carpeta de datos en el proyecto y agréguele una nueva clase PlayersRepository. Será el responsable de almacenar en memoria los datos de los participantes registrados. Complete el nuevo archivo con el contenido que se muestra en el siguiente listado.
Listado: Guardián de los datos de los participantes en la memoria.
using System.Collections.Generic;
using System.Linq;
using SpyOnlineGame.Models;
namespace SpyOnlineGame.Data
{
public static class PlayersRepository
{
private static List<Player> _players = new List<Player>();
private static int _lastId = 1;
public static IEnumerable<Player> All => _players;
public static Player GetById(int id)
{
return All.FirstOrDefault(p => p.Id == id);
}
public static int Add(Player player)
{
player.Id = _lastId++;
_players.Add(player);
return player.Id;
}
public static void Remove(int id)
{
var deleted = GetById(id);
if (deleted is null) return;
_players.Remove(deleted);
}
}
}
A cada miembro agregado a la tienda se le asigna automáticamente una ID de clave única que se utilizará en otras partes de la aplicación. Este identificador identifica de forma única a cada participante del juego. La propia clase PlayersRepository y sus miembros están equipados con la palabra clave estática para que sea más fácil guardar y recuperar datos en diferentes partes de la aplicación.
Guardar información sobre registros de participantes del juego.
Para guardar la información del miembro registrado, debe actualizar el método de acción en el controlador principal. Realice cambios en el controlador como se muestra en la siguiente lista.
Listado: Nuevo método de acción para recibir datos de un formulario en un controlador
using System.Web.Mvc;
using SpyOnlineGame.Data; // Добавить
using SpyOnlineGame.Web.Models;
namespace SpyOnlineGame.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
(HttpPost)
public ActionResult Registration(RegistrationWebModel model)
{
var player = model.Map(); // Добавить
var id = PlayersRepository.Add(player); // Добавить
return RedirectToAction("Index", "Wait", new { id }); // Заменить
}
public ActionResult Rules()
{
return View();
}
}
}
Esta nueva versión del método de acción Registro con el atributo HttpPost toma los datos del formulario HTML como un objeto y guarda ese objeto en el repositorio. En lugar de devolver una vista, ahora utilizamos el método RedirectToAction para redirigir al participante registrado a la página de espera del participante; este es un paso preparatorio antes de que comience el juego. Este enfoque se utiliza con mucha frecuencia en aplicaciones web y es fácil de entender: completar un formulario, obtener datos del formulario, redirigir.
Entonces agregamos una redirección al controlador Esperar para todos los jugadores y su método de acción Índice, pero no agregamos el controlador en sí. El siguiente paso es crear un nuevo controlador, pero antes de eso hay un acuerdo que debe discutirse.
La esencia de la convención es que los datos en representaciones visuales deben enviarse y recibirse sin utilizar tipos primitivos. Esto limpia un poco tanto la presentación visual como el método de acción del controlador. Por lo tanto, antes de agregar el controlador, agregaremos un nuevo modelo web para esperar a los participantes del juego. Cree una nueva carpeta Modelos en la carpeta Web y agregue una nueva clase WaitWebModel a esta carpeta. Esta clase será responsable de pasar datos a vistas visuales. Complete esta clase con el contenido del listado siguiente.
Listado: Modelo web WaitWebModel
using System;
using System.Collections.Generic;
using SpyOnlineGame.Models;
namespace SpyOnlineGame.Web.Models
{
public class WaitWebModel
{
public int Id { get; set; }
public Player Current { get; set; }
public IEnumerable<Player> All { get; set; } = Array.Empty<Player>();
}
}
Este modelo web almacenará datos para generar una lista de participantes registrados y los datos del propio participante registrado. Después del registro, al participante se le asigna un identificador único.
Después de eso, agreguemos este controlador. Agregue un nuevo controlador vacío a la carpeta Controladores y asígnele el nombre WaitController. Complete este nuevo controlador con el contenido del listado siguiente.
Listado: Controlador de espera
using System.Linq;
using System.Web.Mvc;
using SpyOnlineGame.Data;
using SpyOnlineGame.Web.Models;
namespace SpyOnlineGame.Controllers
{
public class WaitController : Controller
{
public ActionResult Index(int id)
{
var all = PlayersRepository.All.ToArray();
var player = PlayersRepository.GetById(id);
if (player is null) return new HttpNotFoundResult();
var model = new WaitWebModel
{
Id = id,
Current = player,
All = all,
};
return View(model);
}
}
}
En este controlador, los datos están preparados para ser mostrados al participante que está esperando a otros jugadores. Se le debe mostrar su nombre y una lista de todos los participantes registrados. Podemos obtener datos sobre el participante actual utilizando el identificador que se pasó del método de acción para registrar al participante. A continuación se debe agregar la representación visual que se mostrará al miembro registrado.
Agregue una nueva carpeta de espera a la carpeta Vistas. Agregue un nuevo objeto visual vacío a esta carpeta. Llene esta vista con contenido nuevo.
Listado: contenido inicial de la página de espera Wait/Index.cshtml
@model WaitWebModel
@{
ViewBag.Title = "Ожидание";
Layout = ~/Views/Shared/_GameLayout.sshtml
}
<h4>@ViewBag.Title</h4>
<p>Ожидание окончания регистрации всех участников игры.</p>
<div class="my-1">
<label>Ваше имя:</label>
<p><strong>@Model.Current.Name</strong></p>
</div>
<div class="my-1">
<p>Все зарегистрированные игроки:</p>
<table class="table table-striped table-bordered">
<thead>
<tr><th>Id</th><th>Имя</th></tr>
</thead>
<tbody>
@foreach (var each in Model.All)
{
<tr>
<th scope="row" class="align-middle">@each.Id</th>
<td class="align-middle">@each.Name</td>
</tr>
}
</tbody>
</table>
</div>
En esta vista utilizamos una plantilla de página diferente a las otras vistas llamada _GameLayout.cshtml. Cree esta plantilla en la carpeta Vistas/Compartida y reemplace completamente su contenido con los que se muestran en el siguiente listado.
Listado: Plantilla para páginas de juegos _GameLayout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Настольная игра "Шпион"</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/htmx")
</head>
<body>
<header>
<nav class="navbar navbar-dark bg-danger">
<div class="container">
<span class="navbar-brand">Настольная игра "Шпион"</span>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-5 pt-3">
@RenderBody()
</main>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
Según esta plantilla, solo se dibujarán las páginas del juego que esperan el registro del jugador y la página del juego.
Puede ejecutar la aplicación y comprobar la funcionalidad del registro de usuarios. Después de hacer clic en el botón de registro en el juego, se le redirigirá a otra página del navegador donde se muestran los datos sobre los participantes registrados en el juego.
Reacción a la entrada de datos
Necesitamos corregir un defecto en la página de espera para todos los jugadores. Si el segundo participante se registra en el juego, el primer participante del juego no lo verá en la lista. El primer participante puede ver al segundo participante solo después de actualizar su página. En la pantalla de abajo, a la izquierda está el registro del primer participante, a la derecha está el siguiente registro de otro participante. Solo después de hacer clic en el botón “Actualizar” del navegador, el primer participante sabrá que se ha registrado otro participante.
Corregiremos este problema agregando una actualización interactiva a la tabla de participantes en esta página. Esto lo haremos utilizando un sistema hipermedia. Agreguemos la biblioteca para soportar el funcionamiento de sistemas hipermedia Htmx.js a la aplicación. Haga clic derecho en el proyecto – “Agregar” – “Biblioteca cliente”. En el cuadro de diálogo que se abre, escriba htmx en la barra de búsqueda y seleccione la última versión de la biblioteca. Después de hacer clic en el botón “Instalar”, los archivos necesarios se agregarán a la carpeta invisible lib/htmx.
Copie el archivo htmx.js de esta carpeta oculta a la carpeta Scripts de la aplicación como se muestra en la siguiente captura de pantalla.
Agregue el registro del paquete al archivo de configuración del paquete App_Config/BundleConfig.cs.
Listado: registro del paquete HTMX en App_Config/BundleConfig.cs
…
bundles.Add(new Bundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js"));
bundles.Add(new Bundle("~/bundles/htmx").Include(
"~/Scripts/htmx.js")); // Добавить
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
…
En la plantilla visual Views/Shared/_Layout.cshtml debe agregar el uso de este nuevo paquete, como se muestra en la siguiente lista.
Listado: Plantilla _Layout.cshtml con un enlace a la página con las reglas del juego.
…
<head>
…
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/htmx") // Добавить
</head>
…
Y a la representación visual de las expectativas de los participantes, es necesario agregar el primer elemento visual hipermedia de actualización periódica del contenido de la página. Edite el archivo Wait/Index.cshtml como se muestra en la siguiente lista.
Listado: página Wait/Index.cshtml con elemento hipermedia
@model WaitWebModel
@{
ViewBag.Title = "Ожидание";
}
<h4>@ViewBag.Title</h4>
<p>Ожидание окончания регистрации всех участников игры.</p>
<div class="my-1">
<label>Ваше имя:</label>
<p><strong>@Model.Current.Name</strong></p>
</div>
<div class="my-1"> // Добавить весь блок
<div id="wait"
hx-get="@Url.Action("Index", "Wait", new { Model.Id })"
hx-trigger="every 1s">
@Html.Partial("Partial/WaitPartial", Model)
</div>
</div>
En lugar de mostrar una tabla, colocamos un elemento hipermedia en esta página. El nuevo atributo hx-trigger con el valor “cada 1s” determina que este elemento enviará una solicitud a la dirección especificada cada segundo y actualizará su contenido. Cree una nueva carpeta Vistas/Espera/Partial y cree una nueva vista parcial WaitPartial.cshtml en ella. En esta vista parcial Wait/Partial/WaitPartial.cshtml debe agregar el código presentado en el siguiente listado. Hemos tomado los elementos de visualización de la tabla de usuarios de la representación visual Wait/Index.cshtml en esta vista parcial.
Listado: Visualización parcial de reproductores Wait/Partial/WaitPartial.cshtml
@model WaitWebModel
<p>Все зарегистрированные игроки:</p>
<table class="table table-striped table-bordered">
<thead>
<tr><th>Id</th><th>Имя</th></tr>
</thead>
<tbody>
@foreach (var each in Model.All)
{
<tr>
<th scope="row" class="align-middle">@each.Id</th>
<td class="align-middle">@each.Name</td>
</tr>
}
</tbody>
</table>
Ahora, cuando se carga la página Wait/Index.cshtml, se representará una página con una vista parcial, que mostrará los datos iniciales de los usuarios registrados. Y sólo entonces, si alguien más se registra en el juego, la lista de visualización debería actualizarse de forma interactiva. Queda por cambiar el método de acción en el controlador para que admita el funcionamiento del sistema hipermedia.
Listado: Controlador de espera con método de soporte hipermedia
using System.Linq;
using System.Web.Mvc;
using SpyOnlineGame.Data;
using SpyOnlineGame.Web.Models;
namespace SpyOnlineGame.Controllers
{
public class WaitController : Controller
{
public ActionResult Index(int id)
{
var all = PlayersRepository.All.ToArray();
var player = PlayersRepository.GetById(id);
if (player is null) return new HttpNotFoundResult();
var model = new WaitWebModel
{
Id = id,
Current = player,
All = all,
};
if (Request.Headers.AllKeys.Contains("hx-request")) // Добавить
{
return PartialView("Partial/WaitPartial", model); // Добавить
}
return View(model);
}
}
}
El método PartialView devuelve la vista parcial especificada en los parámetros. Ahora, para comprobar el funcionamiento del elemento interactivo, ejecuta nuestra aplicación, regístrate en el juego y luego abre otra ventana del navegador cercana y después del segundo registro verás los cambios en la primera ventana. En la primera ventana, como resultado de la siguiente actualización cada dos, se actualizó la visualización de la lista de usuarios registrados.
Entonces, agregamos el primer elemento interactivo a nuestro juego de mesa. Ahora comprende lo fácil que es agregar interactividad a las páginas de aplicaciones web. Agregaremos aún más elementos interactivos en la siguiente parte.
Finalización de la primera parte.
Con esto finaliza la primera parte de mi artículo. En esta parte, se familiarizó con los sistemas hipermedia, comenzó a crear una nueva aplicación: el juego de mesa en línea “Spy” y agregó el primer elemento hipermedia a la página de espera del jugador. En la siguiente parte haremos algunas refactorizaciones interesantes y continuaremos completando esta página con otros elementos interactivos.