Agregando una vista a nuestra aplicación ASP.NET Core MVC
Ahora vamos a continuar donde dejamos en el tutorial de ASP.NET MVC.
En esta sección vamos a modificar la clase HelloWorldController
para que utilice
archivos de plantilla de vista Razor y de esta manera encapsular el proceso
de generar respuestas HTML al cliente.
Creamos archivos de plantilla usando Razor. Los archivos de plantilla Razor tienen la extensión .cshtml (si usamos C#). Proveen una forma elegante de crear una salida HTML usando C#.
Si repasamos lo que vimos en la introducción recordaremos que son archivos HTML comunes solo que tienen algunas expresiones adicionales más que son las que agrega el formato de plantillas Razor.
Actualmente el método Index
retorna una cadena con un mensaje que está hardcodeado
en la clase de controlador. En las clase HelloWorldController
, reemplaza
el método Index
con el siguiente código.
using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;
namespace MvcMovie.Controllers
public IActionResult Index()
{
return View();
}
El código anterior retorna un objeto View
. Esto significa que vamos a usar
una plantilla para generar la respuesta HTML al navegador. Los métodos del controlador
(también conocidos como métodos de acción) tales como el método Index
de arriba, no suelen retornas cadenas de texto simple,
generalmente retornan un IActionResult
(o una clase derivada de ActionResult).
- Hagamos click derecho en la carpeta Views, elijamos Agregar > Nueva carpeta y le pongamos de nombre a la carpeta HelloWorld.
- Hagamos click derecho en la carpeta HelloWold, y elijamos Agregar > Nuevo Elemento.
- En el cuadro de dialogo de Agregar nuevo elemento
- En el campo de búsqueda a la derecha arriba, escribamos vista o view si lo tenemos en inglés.
- Elijamos Vista de Razor
- En el campo de Nombre, cambiemos si es necesario a Index.cshtml.
- Hagamos click en Agregar
Reemplacemos los contenidos de la vista Razor ubicada en el archivo Views/HelloWorld/Index.cshtml con lo siguiente:
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>Hello from our View Template!</p>
Naveguemos a http://localhost:xxxx/HelloWold
. El método Index
en la clase
HelloWorldController
no hizo mucho, ejecutó la sentencia return View();
lo cual especifica que el método debería utilizar un archivo de plantilla
para generar la respuesta al navegador. Porque no especificamos en nombre del archivo
de vista, MVC buscó el archivo Index.cshtml en la carpeta /Views/HelloWorld. La
imagen de abajo muestra la cadena “Hello from our View Template!” hardcodeada
en el archivo cshtml de la vista.
Recordemos que MVC funciona por convención, en este caso el nombre de archivo cshtml que va a buscar es igual al nombre del método del controlador (Index en este caso).
Si la ventana del navegador es pequeña (por ejemplo en un dispositivo móvil), puede que necesitemos tocar en el botón de navegación de Bootstrap arriba de la derecha para ver los links Home, About y Contact.
Cambiando las vistas y las páginas de diseño
Pulsemos en los enlaces del menú(MVCMovie, Home, About). Cada página muestra el mismo diseño. El diseño del menú está implementado en el archivo Views/Shared/_Layout.cshtml. Abramos el archivo Views/Shared/_Layout.cshtml.
Las plantillas
de diseño (en inglés Layout) nos permite especificar en un solo lugar el diseño del HTML
que van a contener todas las páginas de nuestro sitio/app. Busquemos la línea
RenderBody()
.
RenderBody()
es un marcador de posición donde se va a generar todo el contenido
de cada página de vista particular (como la Index.cshtml). Por ejemplo, si
pulsamos en el enlace About, el contenido del archivo
Views/Home/About.cshtml se va a generar donde está ubicado el método RenderBody()
Cambiemos el título del menu y los enlaces en el archivo de diseño
En el elemento título, cambiemos de el texto MvcMovie
a Movie App
. Cambiemos
el texto del enlace en el menú de MvcMovie
a Movie App
y el controlador de
Home
a Movies
como se muestra debajo:
Nota: La versión de ASP.NET Core 2.0 es algo diferente. No contiene
@inject ApplicationInisights
y @Html.Raw(JavaScriptSnippet.FullScript)
.
@inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Movie App</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
@Html.Raw(JavaScriptSnippet.FullScript)
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Movies" asp-action="Index" class="navbar-brand">Movie App</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2017 - MvcMovie</p>
</footer>
</div>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("Scripts", required: false)
</body>
</html>
**Advertencia: ** Todavía no hemos implementado el controlador
Movies
aún, así que si hacemos click en ese enlace vamos a tener un error 404 (no encontrado).
Guardemos los cambios y pulsemos en el enlace About. Notemos como el título ahora dice About - Movie App en lugar de About - MVC Movie
Pulsemos el enlace Contact y notemos que el título y texto del enlace también ahora muestran Movie App. Hemos sido capaces de cambiar una sola vez la plantilla de diseño y todas las páginas del sitio reflejan el cambio en el texto del enlace y en el título.
Las plantillas de diseños es el equivalente en MVC a las Master Pages.
Examinemos el archivo Views/_ViewStart.cshtml:
@{
Layout = "_Layout";
}
El archivo Views/_ViewStart.cshtml: es lo que configura
Views/Shared/_Layout.cshtml como plantilla de diseño
de cada archivo de vista individual.
Podemos utilizar la propiedad Layout para configurar una plantilla de diseño diferente,
o configurarla a null
para no tener ninguna plantilla de diseño.
Cambiemos el título de la vista Index
.
Abrimos Views/HelloWorld/Index.cshtml. Hay dos lugares para hacer el cambio:
- El texto que aparece en el título del navegador
- El encabezado secundario (elemento
<h2>
)
Vamos a hacerlos ligeramente diferente para que veamos cual es el pedazo de código que cambia cada parte de la aplicación.
@{
ViewData["Title"] = "Movie List";
}
<h2>My Movie List</h2>
<p>Hello from our View Template!</p>
La parte ViewData["Title"] = "Movie List";
en el código de arriba
configura la propiedad Title
del diccionario View Data
con el valor
“Movie List”. La propiedad Title
es usada en el elemento HTML <title>
en la plantilla de diseño.
<title>@ViewData["Title"] - Movie App</title>
Guardemos los cambios y naveguemos a http://localhost:xxxx/HelloWorld
.
Notemos que el título del navegador, el encabezado primario
y el encabezado secundario han cambiado. (Si no vemos los cambios en el navegador
puede que estmos viendo contenido cacheado. Presionemos Ctrl+F5 en el navegador
para forzar que se recargue la página desde el servidor.) El título del
navegador es creado con ViewData["Title"]
que pusimos en el archivo de vista
Index.cshtml* y el “- Movie App” adicional que agregamos en la plantilla de
diseño (Layout.cshtml).
Tambiemos notemos que el contenido del archivo de vista Index.cshtml se ha mezclado con el contenido de la plantilla de diseño Views/Shared/_Layout.cshtml y como todo se manda como una única respuesta HTML hacia el navegador. Las plantillas de diseño nos permiten cambiar de manera facil algo y que esos cambios se apliquen en todas las páginas de nuestra aplicación.
Hay información adicional en inglés en la página de Microsoft
Nuestros pedacitos de “datos” (en este caso el mensaje “Hello from our View Template!") está hardcodeado. La aplicación MVC tiene una “V” de Vista y tenemos una “C” de Controlador, pero todavía no tenemos la “M” de módelo.
Pasando datos del Controlador a la Vista
La acciones del controlador se invocan en respuesta a una petición de una URL. La clase del controlador es donde escribimos el código que maneja cada una de esas peticiones de entrada hechas por los navegadores web.
El controlador obtiene datos desde una fuente de datos y decide cual es el tipo de respuesta que le va a enviar al navegador. Los archivos de vista cshtml pueden ser usados por el controlador para generar y formatear una respuesta HTML para el ser mandada al navegador web.
Los controladores son los responsables de proveer los datos requeridos por un archivo de vista cshtml para generar una respuesta. Los archivos de vista cshtml no deberían tener ninguna lógica de diseño o interactuar con la base de datos de manera directa. En lugar de eso, los archivos de vista deberían funcionar solamente con los datos que reciban del controlador. Mantener esta “separación de responsabilidades” nos ayuda a mantener nuestro código limpio, testeable y mantenible.
Actualmente, el método Welcome
en la clase HelloWorldController
toma los parámetros
name
y ID
y emite los valores directamente al navegador. En lugar de tener al
controlador generando una respuesta como un string, cambiemos el controlador
para usar un archivo de vista. Esta plantilla de vista genera una
respuesta dinámica, lo cual requiere que los datos apropiados sean pasados
desde el controlador a la vista para generar la respuesta. Hagamos esto haciendo que
el controlador ponga los datos dinámicos (parámetros) que la vista necesita
en el diccionario ViewData
al cual la vista puede acceder.
Volvamos al archivo HelloWorldController.cs y cambiemos el método Welcome
para que agregue
valores para Message
y NumTimes
al diccionario ViewData
. El diccionario ViewData
es un objeto dinámico, lo que quiere decir que puedes poner lo que quieras en él;
el objeto ViewData
no tiene propiedades definidas hasta que pongamos algo en él.
El sistema de binding de MVC
automáticamente mapea los parámetros con nombre (name
y numTimes
) de la query string
en la barra de direcciones a los parámetros de nuestro método. El archivo completo
HelloWorldController.cs se se muestra a continuación.
using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;
namespace MvcMovie.Controllers
{
public class HelloWorldController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Welcome(string name, int numTimes = 1)
{
ViewData["Message"] = "Hello " + name;
ViewData["NumTimes"] = numTimes;
return View();
}
}
}
El diccionario ViewData
contiene todos los datos que serán pasados a
la vista.
Creemos un archivo de vista para Welcome
en la siguiente ruta
Views/HelloWorld/Welcome.cshtml.
Vamos a crear un bucle en el archivo Welcome.cshtml que muestre el mensaje
“Hello [name]” el número de veces definida por el parámetro NumTimes
.
Reemplacemos los contenidos de Views/HelloWorld/Welcome.cshtml con los siguientes:
@{
ViewData["Title"] = "Welcome";
}
<h2>Welcome</h2>
<ul>
@for (int i = 0; i < (int)ViewData["NumTimes"]; i++)
{
<li>@ViewData["Message"]</li>
}
</ul>
Guardemos los cambios y entremos en la siguiente dirección
http://localhost:xxxx/HelloWorld/Welcome?name=Rick&numtimes=4
Los datos son tomados de la URL y son pasados al controlador de manera automática utilizando
el binder de MVC. El controlador empaca los datos
en un diccionario ViewData
y le pasa este objeto a la vista.
La vista genera los datos como HTML y los envía al navegador.
En el ejemplo de arriba, utilizamos el diccionario ViewData
para pasar datos del controlador
a la vista. Después en esta serie de tutoriales, vamos a usar un modelo para pasar
datos del controlador a la vista.
Pasar datos usando un modelo es siempre preferible antes que usar el diccionario
ViewData
. Ver este enlace
para más información.
Si bien ahora tenemos una especie de modelo, todavía no viene de la base de datos. Tomemos lo que aprendimos y creemos una base de datos de películas en la siguiente parte del tutorial.