Agregando un controlador a una aplicación ASP.NET Core MVC
El patrón arquitectural Modelo-Vista-Controlador (MVC) separa la aplicación en tres componentes principales: Modelo, Vista y Controlador. El patrón MVC te ayuda a crear aplicaciones que son mas testeables y más faciles de actualizar que las aplicaciones tradicionales monolíticas.
Las aplicaciones MVC contienen:
- Modelos: Clases que representan datos en nuestra aplicación. Las clases
de modelo utilizan lógica de validación para hacer cumplir las reglas de negocio para esos datos.
De manera típica, los objetos de modelo toman y guardan datos del estado
del modelo desde y hacia una base de datos. En este tutorial, la clase
de modelo
Movie
obtiene datos de péliculas desde la base de datos, los provee a la vista o los actualiza. Los datos actualizados se guardan nuevamente en la base de datos. - Vistas: Las vistas son los componentes que muestran la interfaz de usuario de la aplicación (UI). Generalmente esta UI muestra los datos del modelo.
- Controladores: Clases que manejan las peticiones de los navegadores web.
Ellos obtienen los datos del modelo y llaman a las plantillas de vista
para devolver una respuesta. En una aplicación MVC, las vistas solo muestran la información;
el controlador maneja y responde a las entradas e interacción del usuario. El controlador
maneja los datos de ruta y las cadenas de conexión y pasa estos valores al modelo. El modelo puede utilizar estos valores para consultar a la base de datos. Por ejemplo,
http://localhost:1234/Home/About
tiene datos de ruta deHome
(el controlador) yAbout
(el método de accion que se va a llamar en el HomeController).http://localhost:1234/Movies/Edit/5
es una solicitud para editar la pélicula con el ID=5 utilizando el controlador Movie. Hablaremos de los datos de ruta más adelante en este tutorial.
El patrón MVC te ayuda a crear aplicaciones que separan los diferentes aspectos de la aplicación (la lógica de interacción, la lógica de negocio y la lógica de UI), mientras provee un bajo acoplamiento entre esos elementos. El patrón especifica a donde deberíamos ubicar cada tipo de lógica en la aplicación. La lógica de UI pertenece a la Vista. La lógica de interacción al Controlador. La lógica de negocio pertenece al Modelo (aunque podemos tener el modelo en capas también). Esta separación nos ayuda a manejar la complejidad cuando hacemos nuestras aplicaciones porque nos permite trabajar en un aspecto de la implementación a la vez sin impactar en el código de otro. Por ejemplo, podemos trabajar en la vista sin depender de la lógica de negocio.
Vamos a cubrir estos conceptos en esta serie de tutoriales y veremos como usarlos para construir una aplicación de peliculas. El proyecto MVC contiene carpetas para los controladores y las vistas.
- En el Explorador de soluciones, hacemos click derecho en Controllers > Agregar > Nuevo elemento…
- En el dialogo de Agregar nuevo elemento seleccionamos Clase de Controlador
- Como nombre le ponemos HelloWorldController
Reemplazamos los contenidos de Controllers/HomeWorldController.cs con los siguientes:
using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;
namespace MvcMovie.Controllers
{
public class HelloWorldController : Controller
{
//
// GET: /HelloWorld/
public string Index()
{
return "Esta es mi acción por defecto...";
}
//
// GET: /HelloWorld/Welcome/
public string Welcome()
{
return "Este es mi método de acción Welcome...";
}
}
}
Cada método public
en un controlador se puede llamar como un endpoint HTTP.
En el ejemplo de arriba, ambos métodos retornan una cadena de texto.
Notemos los comentarios que preceden a cada uno de los métodos.
Un endpoint HTTP es una URL a la que puedo acceder en una aplicación web, tal como
http://localhost:1234/HelloWorld
, y combina el protocolo usado: HTTP
, la dirección de red
del servidor web (incluyendo el puerto TCP): localhost:1234
y la dirección de URI de destino HelloWorld
.
El primer comentario dice que este
es un método HTTP GET
que se invoca agregando “/HelloWorld/” a la URL de base.
Más adelante en el tutorial vamos a usar el motor de scaffolding para
generar métodos HTTP POST
.
Ejecutemos la aplicación en modo sin depurar y agreguemos “HelloWorld” a
la dirección en la barra de direcciones. El método Index
devuelve un string.
MVC invoca a las clases de controlador (y los métodos de acción en ellas) dependiendo de la URL que esté entrando. La lógica de ruteo por defecto usada por MVC usa un formato como este para determinar que código va a invocar:
/[Controller]/[ActionName]/[Parameters]
Podemos configurar el formato de las rutas en el método Configure
del archivo
Startup.cs.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Cuando ejecutamos la aplicación y no proveemos ningun segmento de la URL, estos toman los valores por defecto de “Home” para el controlador y de “Index” para el método del especificado en la línea de template.
La primera parte del segmento de URL determina que clase de controlador ejecutar.
Entonces localhost:xxxx/HelloWorld
se mapea a la clase HomeWorldController
. La segunda
parte del segmento de la URL determina el método de acción en la clase.
Entonces localhost:xxxx/HelloWorld/Index
causaría que se ejecute el método Index
de la clase HomeWorldController
. Notemos que solo tuvimos que navegar a
localhost:xxxx/HelloWorld
y el método Index
fue llamado por defecto.
Esto se debe a que Index
es el método por defecto que se va a llamar en un
controlador si el nombre del método no es especificado de manera explícita.
La tercera parte del segmento de URL (id
) es para los datos de ruta.
Vamos a ver los datos de ruta más adelante en este tutorial.
Naveguemos a http://localhost:xxxx/HelloWorld/Welcome
. El método Welcome
se ejecuta y retorna la cadena “Este es mi método de acción Welcome…".
Para esta URL el controlador es Hello World
y el método de acción Welcome
.
No hemos usado aún la parte de la url para el resto de los parámetros.
Modifiquemos el código para pasar alguna información de parámetros.
Por ejemplo, /HelloWorld/Welcome?name=Rick&numtimes=4
. Cambiemos
el método Welcome
para incluir dos parámetros como se muestra en el
siguiente código.
// GET: /HelloWorld/Welcome/
// Requiere un using System.Text.Encodings.Web;
public string Welcome(string name, int numTimes = 1)
{
return HtmlEncoder.Default.Encode($"Hello {name}, NumTimes is: {numTimes}");
}
El código anterior:
- Usa la característica de C# de parámetros opciones para indicar
que el parámetro
numTimes
toma el valor por defecto 1 si no se pasa ningún valor para ese parámetro. - Usa la función
HtmlEncoder.Default.Encode
para proteger la aplicación de entradas maliciosas (por ejemplo JavaScript). - Usa cadenas interpoladas
Ejecutemos la app y vayamos a:
http://localhost:xxxx/HelloWorld/Welcome?name=Rick&numtimes=4
(Reemplacemos xxxx con tu número de puerto). Puedes probar diferentes valores
para name
y numTimes
en la URL. El sistema
de bindings de MVC mapea los parámetros con nombre
de la query string en la barra de direcciones a los parámetros en nuestro
método.
En la imagen de arriba, el segmento de la URL de parametros
no se usa,
los parámetros name
y numTimes
se pasan como query strings.
El caracter ?
(signo de pregunta) es un separador, lo que sigue
es la queyr string. El caracter &
separa cada parámetro de la query
string.
Reemplacemos el método Welcome
con el código siguiente
public string Welcome(string name, int ID = 1)
{
return HtmlEncoder.Default.Encode($"Hello {name}, ID: {ID}");
}
Ejecutemos la app y entremos la siguiente URL:
http://localhost:xxx/HelloWorld/Welcome/3?name=Rick
Esta vez el tercer segmento de la URL coincide con el parámetro
de ruta id
. El método Welcome
contiene un parámetro
id
que coincide con la plantilla de URL que está en el método
MapRoute
. El signo de pregunta ?
(en id?
) indica
que el parámetro id
es opcional.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
En estos ejemplos el controlladores ha estado haciendo la porción “VC” de MVC, o sea el trabajo de la vista y del controlador. El controlador está retornando el HTML de manera directa. Generalmente no queremos que el controlador retorne el HTML de manera directa, dado que puede dar lugar a código muy complejo y dificil de mantener. En lugar de eso, lo más normal es que usemos una plantilla de vista Razor para ayudar a generar la respuesta HTML. Eso es lo que vamos a hacer en la próxima parte del tutorial.
En Visual Studio, en modo sin depurar (Ctrl+F5), no necesitas compilar la aplicación después de cambiar el código. Simplemente guardamos el archivo, actualizamos el navegador y podemos ver los cambios.