Está en la página 1de 55

Escrito por: Horacio Aldo Tore

Aprendiendo ASP.NET MVC 5


guiado por un desarrollo.
1. Objetivo ..................................................................................................................................................................... 1
2. Versiones ................................................................................................................................................................... 1
3. Consejo al lector........................................................................................................................................................ 2
4. Base de datos ............................................................................................................................................................ 3
5. Acceso a datos .......................................................................................................................................................... 3
6. Probando el acceso a datos .................................................................................................................................... 12
7. ¿Por dónde empezar, por M, por V o por C? .......................................................................................................... 13
8. Desarrollo del o los modelos................................................................................................................................... 14
9. Scaffolding ............................................................................................................................................................... 16
10. Creación de los controladores ............................................................................................................................ 17
11. Desarrollo del controlador “HistogramaController”, “Ver” ................................................................................ 21
12. Desarrollo de la vista “Ver” ................................................................................................................................. 22
13. Desarrollo del controlador “CandidatoController”, “Insert” .............................................................................. 26
14. Desarrollo de la vista “Insert” ............................................................................................................................. 28
15. Desarrollo del controlador “CandidatoController”, “Edit” ................................................................................. 30
16. Desarrollo de la vista “Edit” ................................................................................................................................ 32
17. Desarrollo de las vistas parciales ........................................................................................................................ 36
17.1. Desarrollo de la vista parcial “_Titulo” ........................................................................................................... 37
17.2. Desarrollo de la vista parcial “_Menu” ........................................................................................................... 39
18. Validaciones ........................................................................................................................................................ 44
18.1. Validaciones por atributos .............................................................................................................................. 44
18.2. Validaciones utilizando el método AddModelError ........................................................................................ 52
19. Conclusión ........................................................................................................................................................... 54
20. Referencias.......................................................................................................................................................... 55

1. Objetivo: Explicar los conceptos básicos de la tecnología MVC (Model View Controller), utilizando como guía
el desarrollo una aplicación WEB de ABMC (Altas, Bajas, Modificaciones, Consultas) sobre una base de datos SQL
Server.

2. Versiones: Para ser más precisos utilizaremos Microsoft ASP.NET MVC 5 que viene con Visual Studio 2013 y
Microsoft SQL Server 2014.

1
Escrito por: Horacio Aldo Tore

3. Consejo al lector: Antes de seguir invirtiendo tiempo leyendo esta publicación, el lector podrá analizar
rápidamente las siguientes capturas de pantalla y de este modo, juzgar si este documento es lo que estaba
buscando.

Figura 1

Figura 2

Figura 3

Figura 4

2
Escrito por: Horacio Aldo Tore

4. Base de datos: Iniciaremos el desarrollo desde el extremo de “back-end” hasta llegar al “front-end”, para
esto deberemos creara una base de datos llamada “EleccionesDB” y luego ejecutar el siguiente script para crear
la tabla sobre la cual persistiremos la información.

Figura 5
use EleccionesDB;

CREATE TABLE [dbo].[Candidatos] (


[CandidatoId] INT IDENTITY (1, 1) NOT NULL,
[Nombre] NVARCHAR (50) NOT NULL,
[PorcentajeDeVotos] INT NOT NULL,
CONSTRAINT [PK_Candidatos] PRIMARY KEY CLUSTERED ([CandidatoId] ASC)
);

5. Acceso a datos: Acceso a datos mediante Entity Framework, para esto debemos crear un directorio en el
cual se alojará el código generado a partir de la base de datos (database first), en nuestro caso lo llamaremos
DAL (Data Access Layer).

Figura 6

3
Escrito por: Horacio Aldo Tore

Seleccionando el directorio “DAL” y mediante el menú contextual que aparece al presionar el botón derecho
del mouse, escogemos “New Item”, como vemos en la siguiente captura de pantalla.

Figura 7

Figura 8

4
Escrito por: Horacio Aldo Tore

La capa de persistencia se genera leyendo la estructura o esquema de la base de datos, seleccionamos “EF
Designer from database”, como se muestra en la siguiente figura:

Figura 9

5
Escrito por: Horacio Aldo Tore

Figura 10

6
Escrito por: Horacio Aldo Tore

Indicamos el nombre del servidor y de la base de datos, tal como se muestra a continuación.

Figura 11

7
Escrito por: Horacio Aldo Tore

Figura 12

8
Escrito por: Horacio Aldo Tore

Figura 13

9
Escrito por: Horacio Aldo Tore

Figura 14

10
Escrito por: Horacio Aldo Tore

Figura 15

Observemos que se ha generado el "Connection String" o "Cadena de conexión" en el archivo “Web.config”,


tal como muestra la siguiente captura de pantalla.

Figura 16

11
Escrito por: Horacio Aldo Tore

En la siguiente captura de pantalla se ha destacado el nombre del servidor y de la base de datos sobre la cual
persistirá y leerá nuestra aplicación.

Figura 17

6. Probando el acceso a datos: Prueba del ORM del tipo Entity Framework. Si la generación de código
de persistencia a partir de la base de datos fue exitosa ya estaríamos en condiciones de escribir el siguiente
código para leer todos los registros (candidatos) desde la tabla de la base de datos.

Figura 18

12
Escrito por: Horacio Aldo Tore

Otro ejemplo sería el siguiente que nos permite eliminar un candidato dado el valor de su clave primaria
(CandidatoId).

Figura 19

En suma, ya tendríamos solucionado el acceso a datos.

7. ¿Por dónde empezar, por M, por V o por C?: Al iniciar con MVC, nos hacemos la siguiente
pregunta

¿Qué debo desarrollar primero la M, la V o la C?

La respuesta está en la Figura 23, primero debemos desarrollar la M (Model) ya que no depende de C
(Controller) ni de V (View), en otras palabras, es independiente.

¿Y con que seguimos, C o V?

Lamentablemente la Figura 23 nos da una mala noticia, existe un ciclo de dependencias entre C y V, en otras
palabras, C depende de V y viceversa, razón por la cual no podemos decidir con cual componente continuar
el desarrollo. La decisión la podremos tomar añadiendo un estándar relacionado con el andamiaje
(Scaffolding) o estructura de directorios y archivos, como sigue:

Figura 20
Los nombres de los directorios donde se almacenarán los archivos que contienen el código de las vistas,
deben coincidir con los nombres de los controladores.
Los nombres de los archivos que contienen el código de las vistas deben coincidir con el nombre de los
“Action method” de los controladores.

De la Figura 20, deducimos entonces que primero deben existir los controladores, razón por la cual aremos
un “desarrollo superficial” de estos y al final un “desarrollo superficial” de las vistas.

En resumen, el orden de los módulos a desarrollar será como sigue:

Figura 21
1º el modelo.
2º el controlador.
3º la vista.

13
Escrito por: Horacio Aldo Tore

Con el término “desarrollo superficial” me refiero a que no es necesario desarrollar por completo el código
de los controladores, solo los “Action method” con el atributo [HttpGet] con su cuerpo vacío, que veremos
más adelante. Luego del desarrollo de los controladores, aremos un “desarrollo superficial” de las vistas, de
modo que ya tengamos la estructura de directorios y archivos lista para iniciar las pruebas de comunicación
entre las vistas y los “Action method” de los controladores, o en otras palabras entre el cliente y servidor
web, aunque estas no muestren más que una página en blanco, pero con un suceso muy importante, no hay
errores, esto implica que la comunicación funciona.
Luego de que comprobemos el existo en la comunicación, podemos iniciar el “desarrollo completo” de los
controladores y vistas, que habíamos dejado pendientes.

El siguiente sería un resumen de lo antes detallado:

Figura 22
1 Es recomendable que cada modelo pueda ser utilizado por uno o más controladores, la inversa no es
una buena práctica.
2 Desarrollar por completo del modelo.
3 “desarrollo superficial” de los “Action method” de los controladores, solo firma y con el cuerpo en
blanco, [HttpGet] y opcional [HttpPost].
4 “desarrollo superficial” las vista, con el contenido en blanco. Los archivos tendrán los mismos
nombres que los “Action method” definidos en el paso anterior y se encontrarían bajo un directorio
que posee el mismo nombre que el controlador.
5 Realizar pruebas de comunicación HTTP, entre las vistas y su “Action method” [HttpGet] respectivo,
utilizando para esto el navegador web.

8. Desarrollo del o los modelos: La clase Model o mejor dicho ViewModel o representación en objetos
de la vista, cuidado de la vista no del negocio, es independiente, ya que tanto la C (el controlador “controller”)
como V (la vista “View”) no lo son porque que dependen del Modelo. Recordemos que en el patrón MVC, el
modelo es el único componente independiente y por ese motivo iniciamos primero su desarrollo, ver Figura 21.
La siguiente figura muestra el diagrama de dependencias entre el modelo, la vista y el controlador, la flecha debe
leerse como “depende de”, por ejemplo, la vista depende del modelo, la vista depende del controlador (ver línea
punteada o de segmentos), etc.

Figura 23

Las flechas solidas indican una dependencia fuerte mientras que las punteadas indican una dependencia
mas debil y que en algunos casos puede no existir.

14
Escrito por: Horacio Aldo Tore

Observando la Figura 1, tal como un dibujante observa y bosqueja con un lápiz sobre el papel, podemos
desarrollar la clase que será la representación en objetos de la vista o interfaz de usuario expuesta, como
sigue:

Figura 24

Notemos que la clase “HistogramaViewModel” solo posee una propiedad, ver línea (14), que representa la
lista de candidatos que se muestra en la interfaz de usuario de la Figura 1.
Si bien existen varios estándares, aquí utilizaremos aquel que propone que todas las clases que representan
el modelo terminen con el postfijo “ViewModel”, de este modo la clase se llama “HistogramaViewModel”
en lugar de “Histograma”.

En la línea (5) observamos el “using” que incluye el “namespace” al que pertenece la clase “Candidato”
utilizada por la lista de la línea (14). Dentro del “namespace” “MVCElecciones.DAL” se encuentra el código
fuente de persistencia que emos generado con la herramienta “entity data model wizard”, siendo la clase
“Candidato” una clase generada, una entidad.

Ahora observando la Figura 2 y la Figura 3, podemos desarrollar la clase que será la representación en
objetos de ambas vistas, si, el mismo modelo será utilizado por dos vistas distintas. Si bien existen varios
estándares, aquí utilizaremos aquel que propone que todas las clases que representan el modelo terminen
con el postfijo “ViewModel”, de este modo la clase se llamará “CandidatoViewModel” en lugar de
“Candidato”, así evitaremos conflictos de nombres de clase con la entidad del negocio “Candidato” que se
encuentra bajo el namespace “MVCElecciones.DAL”. Otros estándares proponen el uso del postfijo “VM”
como una abreviatura de “ViewModel”, lo cual nos facilitaría la escritura.

Figura 25

15
Escrito por: Horacio Aldo Tore

En las líneas (10, 11 y 12) de la Figura 25, vemos las tres propiedades que existen como representación de
los tres campos que se ven en la Figura 2 y en los cuales el usuario ingresaría sus respectivos valores. Este
modelo será utilizado tanto para la vista de la Figura 2 como para la de la Figura 3 ya que ambos coinciden.
Estas clases se encuentran en el directorio “Models” tal como muestra la siguiente figura:

Figura 26

9. Scaffolding: El Scaffolding o andamiaje en MVC, trata sobre la estructura de directorios y los nombres que
los archivos deben tener según el patrón de diseño “Convention over configuration (CoC)”, algunas de estas
reglas se enuncian en la Figura 20. Esto nos lleva como paso seguido a crear los controladores y luego las vistas,
ya que estas últimas deben ubicarse dentro de directorios que se llaman como los controladores, sin el postfijo
“Controller”. Es el propio Visual Studio 2013, quien agrega el postfijo “Controller” a cada controlador y quien
crea los directorios con el mismo nombre de los controladores dentro del directorio “Views”, tal como muestra
la siguiente captura de pantalla:

16
Escrito por: Horacio Aldo Tore

Figura 27

10. Creación de los controladores: Ya emos terminado los modelos ahora continuamos con la creación
de los controladores.

Figura 28

17
Escrito por: Horacio Aldo Tore

Figura 29

18
Escrito por: Horacio Aldo Tore

Figura 30

Luego de hacer clic sobre el botón “Add” de la Figura 30, el IDE de Visual Studio 2013, se encargará de crear
el archivo “CandidatoController.cs” y dentro del directorio “Views”, creará el directorio “Candidato” que
contendrá las vistas para el controlador como se muestra en la Figura 31. Luego lo más común es que cada
archivo de vista se llame como el “Action Method” homólogo de la clase “CandidatoController”, así si existe
un “Action Method” llamado “A” lo más común es que exista una vista llamada “A” dentro del directorio
“Candidato”.

Figura 31

19
Escrito por: Horacio Aldo Tore

Realizando el mismo procedimiento, pero en lugar de “Candidato” utilizaremos “Histograma” y creamos su


controlador respectivo, tal como se ve en la imagen siguiente.

Figura 32

20
Escrito por: Horacio Aldo Tore

11. Desarrollo del controlador “HistogramaController”, “Ver”: Los controladores son clases
que heredan de la clase “Controller” y que poseen métodos que se conocen con el nombre de “Action method”,
lo más común es que retornen una vista y le pasen a esta ultima el modelo, para que construya la interfaz de
usuario (HTML, JavaScript, CSS, etc.) que se mostrará en el navegador o browser. Aunque no es una regla
estricta, lo más frecuente es que cada vista se llame de la misma manera que el “Action method” que la utiliza
por “Convention over configuration (CoC)”.
Al crear un nuevo controlador llamado “Histograma”, el entorno de desarrollo de Visual Studio crea el siguiente
código que contiene un “Action method” llamado “Index”, lo renombraremos como “Ver” ya que queremos que
la vista se llame de ese modo, ver Figura 34.

Figura 33

21
Escrito por: Horacio Aldo Tore

Crearemos un “Action method” llamado “Ver”, lo cual demandará crear una vista llamada “Ver”, no nos
interesa completar el cuerpo del método o el código de la vista, solo queremos armar el andamiaje
(Scaffolding) y verificar que funcione la cadena de comunicaciones HTTP.

Figura 34

Como por defecto el “Action method” es “[HttpGet]” el código de la Figura 34 se comporta de la misma
forma que el de la Figura 35, solo que en el primer caso, esta característica del protocolo HTTP está implícita
y en la segunda explícita.

Figura 35

12. Desarrollo de la vista “Ver”: Solo crearemos una vista vacía para verificar que la invocación a la URL
“http://localhost:57513/Histograma/Ver” funcione, la URL por defecto se forma mediante el nombre del
servidor “localhost:57513”, seguido por el nombre del controlador “Histograma” más el nombre del “Action
method” “Ver”. La prueba será sencilla, bastará escribir la URL en un navegador web.

La vista se crea utilizando el menú contextual sobre el directorio que se encuentra en “Views” y que se llama
igual que el controlador, en este caso el directorio “Histograma”, como sigue:

22
Escrito por: Horacio Aldo Tore

Figura 36

Figura 37

Observemos que se ha creado el archivo de la vista “Ver.cshtml”, que coincide con el nombre del “Action
method”), bajo el directorio “Histograma” que coincide con el nombre del controlador, bajo el directorio
“Views” que es donde van a ir a parar todas las vistas. Esta estructura o andamiaje de directorios y archivos
es consecuencia del patrón de diseño “Convention over configuration (CoC)”. Podemos decir como regla
general, que los directorios de las vistas coinciden con los nombres de los controladores y cada vista coincide
con el nombre del “Action method”. De este modo, el directorio “Histograma” contendrá todas las vistas
utilizadas por el controlador que posee el mismo nombre.

23
Escrito por: Horacio Aldo Tore

Figura 38

Si todo se ha hecho correctamente deberíamos ser capaces de invocar al “Action method” “Ver” utilizando el
navegador mediante la URL : “http://localhost:57513/Histograma/Ver” y observar una página en blanco,
indicador del éxito de la comunicación entre el “Action method” “Ver” y la vista “Ver”, tal como sigue:

Figura 39

Otra prueba es colocar un “breakpoint” en el “Action method” “Ver” y comprobar que el navegador lo
invoca vía [HttpGet], tal como muestra la siguiente captura de pantalla:

Figura 40

24
Escrito por: Horacio Aldo Tore

Terminada la prueba ya estamos en condiciones de realizar el desarrollo de la vista, la línea (1) de la Figura
41, indica el modelo o parámetro que recibe la vista, que será pasado por el “Action method” “Ver”.
Notemos que al llamarse la vista igual que el “Action method” no precisamos especificar el nombre de esta
última al ser invocada por el controlador. En caso de que la vista no se llamase como el controlador podemos
especificar una en particular como sigue: “return View("Ver", model);” otra manera seria indicar la URL del
siguiente modo: “return View("~/Views/Histograma/Ver.cshtml", model);”.

Una vez recibido el modelo por la vista (1), solo nos resta iterar por cada uno de los candidatos en la lista (3)
y generar el HTML de una tabla (11) variando su ancho según el valor de “candidato.PorcentajeDeVotos”,
el resultado obtenido será el que se muestra en la Figura 1, en la cual cada barra horizontal verde es una
tabla HTML.

Podemos ver en (5) el HTML correspondiente a un hyperlink o enlace “<a>”, funcionalmente la aplicación da
la posibilidad al usuario de modificar las propiedades de un candidato determinado tal como se ve en la
Figura 1, navegando a la Figura 2 en la cual vemos la edición de “Sadosky”. ¿Clementina y Sadosky?, bueno
ese es otro tema.

El helper “Url.Action” (5) nos genera la ruta o URL correcta para poder invocar vía [httpget] al “Action
method” "Edit" del controlador "Candidato" pasándole como parámetro el valor “candidato.CandidatoId”,
clave primaria que identifica inequívocamente a un candidato. De este modo podemos ver en la Figura 2, la
URL formada “http://localhost:57513/Candidato/Edit/1”.

Figura 41

En la Figura 42, solo se ha reemplazado el código de (5), aunque no es conveniente desarrollarlo de esta otra
forma, mejor es usando el helper “Url.Action” ya que este tiene en cuenta los formatos de ruta o routing
que tengamos especificado en el archivo “RouteConfig.cs”. Por defecto el formato de ruta en MVC obedece
el siguiente patrón: “{Controlador} / {Acción} / {Id}” por este motivo la URL hardcodeada en la línea (5)
funciona, pero si cambiase el formato por defecto a “{Acción} / {Controlador} /{Id}” dejaría de hacerlo. En
resumen, el código de la Figura 41 seguiría funcionando, mientras que el de la Figura 42 no lo hará.
25
Escrito por: Horacio Aldo Tore

Figura 42

Si bien trataremos más adelante el tema de vistas parciales, solo agregaremos las líneas de código (3 y 4)
que son responsables de invocarlas y generar el código HTML del título y el menú, comunes a todas las
interfaces de usuario, tal como se ve a continuación para el caso de nuestra vista “Ver.cshtml”.

Figura 43

13. Desarrollo del controlador “CandidatoController”, “Insert”: La Figura 44 muestra el


controlador “CandidatoController”, todos los controladores terminan con el posfijo “Controller”, con el cual se
comunica la vista “Insert” para inicializarse y persistir los valores ingresados por el usuario en la base de datos.
Observemos que existen dos “Action method”, el de la línea (14) y el de la línea (20). El primero tiene un
atributo “[HttpGet]” (también llamado Query string) y el segundo uno del tipo “[HttpPost]”, especificando los
métodos que se utilizaran para comunicarse mediante el protocolo HTTP. El primer método es responsable de

26
Escrito por: Horacio Aldo Tore

inicializar la vista y mostrarla, bastara tipear “http://localhost:57513/Candidato/Insert” como URL en el


navegador web para que se llame a este método. En este caso enviara a la misma un modelo nulo para que los
campos aparezcan en blanco, ver Figura 3. Una vez mostrada la vista en el navegador, el usuario completa los
valores de los campos pedidos y al hacer clic sobre el único botón existente enviará los valores mediante el
método “POST”, siendo estos recepcionados por el “Action method” “Insert” de la línea (20).

Observemos con qué facilidad y con qué nivel de abstracción con respecto al protocolo HTTP, el método (20)
recibe los datos ingresados por el usuario, esto se conoce como “Model binding”, estableciendo un puente entre
la solicitud HTTP y los “Action method” de los controladores para que no tengamos que preocuparnos por los
detalles a bajo nivel de la comunicación, lo que nos importa son los valores y esto es justo lo que tenemos listo
para consumir.

La línea (22) solo hace una validación funcional antes de realizar la persistencia en la base de datos, en la (23)
que llama a un método que utiliza Entity Framework, luego la (24) pasa el modelo a la vista “Insert” para que
esta pueda mostrar todas las propiedades del modelo del tipo “CandidatoViewModel”, pero en particular el
valor de la propiedad “CandidatoId” establecida por la base de datos luego de la inserción del registro y
mostrada en modo solo lectura por la vista, en la línea (15) de la Figura 46.

En la línea (27) se encuentra un método que no es un “Action method” ya que es privado y por lo tanto
inaccesible vía HTTP, este es el encargado de persistir al nuevo candidato como un nuevo registro en la base de
datos y de establecer el valor de la propiedad “CandidatoId” del modelo, ver línea (37). Se utiliza Entity
Framework como ORM (Object Relational Mapper ), la generación de esta capa de persistencia a partir de la
base de datos ya fue tratada a partir de la Figura 6, pero es aquí donde se utiliza creando una entidad del tipo
“Candidato” (29), estableciendo los valores de sus propiedades a partir del modelo (30 y 31) y creando un
contexto (33) para adicionar la entidad (34), pero es en realidad en el método “context.SaveChanges()” (35)
cuando se llevara a cabo la inserción del registro en la base de datos, luego la propiedad
“candidato.CandidatoId” (37) se establecerá al valor dado por la base de datos, debido al comportamiento auto
incremental del campo.

Figura 44

27
Escrito por: Horacio Aldo Tore

14. Desarrollo de la vista “Insert”: Debemos basarnos en la interfaz de usuario expuesta en Figura 3 y en
el modelo de la Figura 25 para el desarrollo del código de esta vista.
En la línea (1) de la Figura 46 se encuentra el modelo como un parámetro de entrada, tal como pasa en la
vista parcial de “_Titulo” de la Figura 65, solo que este modelo no es del tipo string, sino una instancia de la
clase “CandidatoViewModel” , definida en la Figura 25. Las líneas (8 y 9) ya fueron explicadas con
anterioridad y son responsables de insertar el título y el menú correspondientes en esta vista y comunes a
todas las demás.

Figura 45
En MVC él envió de formularios es sinónimo de POST, en otras palabras, de HTTP método POST.

En MVC él envió de formularios es sinónimo de POST, en otras palabras, de HTTP método POST, este
formulario inicia en la línea 12 y termina en la 28 y está definido en la línea 11. Cuando el usuario realice un
clic sobre el botón de “submit” (27) todos los valores ingresados en los helpers “@Html.EditorFor” viajarán
al servidor y serán recibidos por “Action method” “Insert” del controlador “CandidatoController” tal como se
ve en el código de la Figura 44 línea (20).

Si bien podemos indicarle a Html.BeginForm() el nombre del controlador y del “Action method”, por
simplicidad emos preferido su utilización sin ningún parámetro, de esta manera invocará al mismo
controlador y “Action method” que fue utilizado para inicializar la página actual, en otras palabras, invocará

28
Escrito por: Horacio Aldo Tore

al controlador “CandidatoController” y “Action method” “Insert” que esta adornado con el atributo
[HttpPost].

Así “Insert” con [HttpGet] inicializa e “Insert” con [HttpPost] persiste los valores ingresados por el usuario
en el formulario.

Debemos destacar el uso de la pareja de helpers “Html.LabelFor” y “Html.EditorFor” utilizados en las líneas
19, 20 y 23, 24. El primero es el encargado de mostrar el nombre de la propiedad y el segundo el control
más adecuado para editar esa propiedad.

El caso de de la propiedad “CandidatoId” es especial y se ha utilizado la pareja de helpers “Html.LabelFor”


(13) y “Html.DisplayFor” (15) ya que esta propiedad del modelo se muestra en modo solo lectura y su valor
será conocido luego de la inserción del registro en la base de datos, debido a que el campo es del tipo “INT
IDENTITY” tal como se observa en la Figura 4, siendo su comportamiento del tipo auto incremental. De este
modo “Html.LabelFor” muestra el nombre de la propiedad y “Html.DisplayFor” muestra su valor, en modo
no editable.

Figura 46

29
Escrito por: Horacio Aldo Tore

15. Desarrollo del controlador “CandidatoController”, “Edit”: Realizaremos el desarrollo


superficial de “Action method” “Edit” decorándolo con el atributo “[HttpGet]”, luego desarrollaremos la vista
también llamada “Edit”, para probar la comunicación entre ambos.

La siguiente figura muestra el “Action method” que recibe por parámetro el valor de la clave primaria del
registro con la cual se inicializara la vista, al no especificarse una vista la instrucción “return View()” llamara a la
vista que posea el mismo nombre que el método y que se encuentre en el directorio “Views\Candidato”, ver
Figura 31.

Figura 47

La siguiente figura muestra la vista “Edit” en blanco (sin código alguno).

Figura 48

Ahora podemos tipear la siguiente URL en nuestro browser y si todo funciona bien deberíamos ver la
siguiente captura de pantalla, en blanco, pero sin ningún error. Esto es señal de que el “Action method” es
accesible perfectamente vía HTTP y que este invoca a la vista del mismo nombre.

Figura 49

30
Escrito por: Horacio Aldo Tore

Otra prueba es establecer un “breakpoint” (66) y verificar que el valor del “1” que figura como parte de la
URL, llegue como parámetro de nuestro “Action method” “Ver”, tal como se muestra a continuación.

Figura 50

Ahora si estamos en condiciones de realizar el desarrollo total del “Action method” que utilizará “Entity
Framework” para encontrar al candidato por su id en la base de datos y pasárselo como parámetro a la vista
(74), para inicializarla y que esta lo muestre al usuario.

Figura 51

Solo comentaremos sobre la Figura 51, que recuperamos el candidato utilizando el método “Find” (67), que
busca por el valor de la clave primaria, razón por la cual solo retorna una entidad y no una colección de
entidades del tipo “Candidato”.

La siguiente Figura 52, muestra una sobrecarga del “Action method” “Edit”, pero este será invocado
mediante “[HttpPost]” ver línea (77) en lugar de “[HttpGet]” y será responsable de persistir la entidad o
eliminarla de la base de datos.

En la firma del método (78), es el “Model binding” el que nos brinda la facilidad de recibir los valores que
tipeo el usuario como una instancia de la clase “CandidatoViewModel”, haciéndonos transparente la
recepción y desempaquetado de la información, que fue transmitida vía “HTTP” desde el browser del cliente.

Los otros dos parámetros nos indican que botón del tipo “submit” fue el que causo la transmisión vía
HttpPost, o en otras palabras sobre cual botón realizo clic el usuario de nuestra aplicación, ver Figura 2.

Figura 52

31
Escrito por: Horacio Aldo Tore

Los nombres de los parámetros “buttonSave” y “buttonDelete” (78) no pueden ser elegidos arbitrariamente
o por gusto del desarrollador, sino que deben coincidir con la propiedad “name” de los tags de HTML que
tienen los mismos en la vista que aún no hemos desarrollado pero que nos adelanta la Figura 53.

Figura 53

16. Desarrollo de la vista “Edit”: Para crear la vista solo debemos seleccionar la carpeta
“Views\Candidato” ya que será una vista para el controlador “CandidatoController”.

Figura 54

32
Escrito por: Horacio Aldo Tore

El nombre de la vista será “Edit” ya que de ese modo se llama el “Action method” del controlador
“CandidatoController”, la vista no será parcial como si lo son “_Menu” y “_Titulo”, así que no marcamos
esta opción.

Figura 55

El entorno de desarrollo de Visual Studio 2013 nos crea el siguiente código como una plantilla de la vista,
luego desarrollaremos el resto utilizando la sintaxis “Razor” para trabajar con las propiedades del modelo y
así completar la parte dinámica (variable) del código HTML.

33
Escrito por: Horacio Aldo Tore

Figura 56

En la línea (1) del código de la Figura 57, podemos ver el parámetro que es el modelo que envía el “Action
method” “Edit” “[HttpGet]” de la Figura 51 en su línea (74). Las vistas solo pueden tener un modelo, por
ende, solo un parámetro que será utilizado luego para generar la parte dinámica o variable de la misma.
Observemos que el parámetro es “@model” (1) mientras que su uso como marcador de reemplazo de
propiedades por valores es “Model” (15).
En la línea (15) se pasa como parámetro a la vista parcial “_Titulo”, el valor que debe presentar, mostrando
el nombre del candidato que se está editando, ver Figura 2.
El formulario inicializado en (18) abarca desde (19) a (37) y recordemos que: “en MVC él envió de
formularios es sinónimo de POST, en otras palabras, de HTTP método POST”, tal como se enunció en la
Figura 45.
Ya emos tratado el uso de la pareja de helpers “Html.LabelFor” y “Html.EditorFor” y de la pareja
“Html.LabelFor” y “Html.DisplayFor” cuando se desarrolló la vista “Insert”, en este caso cumplen el mismo
objetivo, lo único diferente es que debemos enviar al servidor, entiéndase al controlador, el valor de la clave
primaria “CandidatoId” y esto no se logra con “Html.DisplayFor” razón por la cual emos utilizado el viejo
truco de generar un campo oculto al usuario, en este caso generado por el helper “Html.HiddenFor”, los
campos ocultos si son enviados como parte del formulario inicializado en la línea (18).
Mientras las propiedades “Nombre” (28) y “PorcentajeDeVotos” (32) son editables la propiedad
“CandidatoId” (22) no lo es y la aplicación solo muestra su valor al usuario.
Los helpers “Html.LabelFor”, “Html.EditorFor”, “Html.LabelFor”, “Html.DisplayFor” y “Html.HiddenFor”
utilizan expresiones lambda como parámetro, para escribir de forma abreviada la indicación del valor y el
tipo de la propiedad del modelo que deben mostrar. De este modo la aplicación impedirá el ingreso de letras
para el campo “PorcentajeDeVotos” que es del tipo numérico, sin que tengamos que realizar desarrollo
alguno.

Figura 57

34
Escrito por: Horacio Aldo Tore

La Figura 58 trata de mostrar la relación existente entre los helpers, los botones de la vista y los parámetros
del “Action method” “Edit” “[HttpPost]” esto se conoce como “Model binding” y es un puente entre la
solicitud (request) HTTP y los “Action method”.
Mientras los helpers “Html.EditorFor” y “Html.HiddenFor” se conectan con las propiedades de parámetro
“model” los botones del tipo “submit” lo hacen con los parámetros “buttonSave” y “buttonDelete”, es por
este motivo que la propiedad “name” de los botones debe coincidir con el nombre del parámetro, entonces
damos primero el nombre a los parámetros y después a los botones o viceversa, el objetivo es que se llamen
igual para que se produzca el “Model binding”.
Para discriminar que botón causo el envió del formulario o en otras palabras sobre cual realizo clic el
usuario, solo debemos discriminar aquel que es distinto de nulo, por ejemplo, si el unario realizo un clic
sobre el botón "Grabar" entonces el parámetro “buttonSave” tendrá el valor "Grabar" mientras que el
parámetro “buttonDelete” tendrá un valor “null”, que es lo que hace el código de la Figura 52, luego realiza
una eliminación o una persistencia según corresponda.

Figura 58

35
Escrito por: Horacio Aldo Tore

17. Desarrollo de las vistas parciales: Con el objetivo de presentar un marco común que se repite en
todas las interfaces de usuario, formado por el título y un pequeño menú, como podemos ver en la Figura 1,
Figura 2 y Figura 3, utilizaremos vistas parciales ya que nos brindan la posibilidad de centralizar el código común
en una sola vista que puede ser invocada desde las que precisan utilizarla, tal como se muestra en la siguiente
figura.

Figura 59

De este modo si necesitamos modificar el menú, ya sea agregando otro ítem o simplemente cambiando su
color, bastara hacerlo en la vista parcial para que el resto tome estas mejoras.

Lo recomendable es que las vistas parciales se creen dentro de un directorio llamado “Shared” para que
puedan ser accedidas por cualquiera de las vistas que las precisan, sin tener la necesidad de especificar
36
Escrito por: Horacio Aldo Tore

complejas rutas, como por ejemplo “@Html.Partial("~/Views/Shared/_Titulo.cshtml", "Histograma")”.


Si bien no es necesario, es un formato estándar que comiencen con “underscore” (_) por ejemplo
“_Menu.cshtml”. El directorio “Shared” no tiene controlador asociado llamado “SharedController”, es un
directorio especial utilizado para compartir vistas parciales.

La siguiente figura muestra la estructura de directorios y los archivos de vistas parciales para nuestro
proyecto.

Figura 60

17.1. Desarrollo de la vista parcial “_Titulo”: Lo único a destacar de esta vista parcial, es
que recibe como parámetro un modelo identificado con “@model” ver Figura 64, línea (1), que no es otra
cosa más que el valor del título que debe mostrar. Para crearla debemos seguir los siguientes pasos:

Figura 61

37
Escrito por: Horacio Aldo Tore

Figura 62

Notemos en la siguiente figura, que las vistas parciales se crean sin código alguno a diferencia de las que son
completas, que poseen al momento de ser creadas por el entorno de desarrollo los tags de <html>, <head>

38
Escrito por: Horacio Aldo Tore

y <body>. Esto es lógico, ya que las vistas parciales serán usadas como parte de una vista completa, entonces
no pueden repetir los tags que ya existen en la vista completa que las incluye.

Figura 63

Figura 64

La siguiente figura es una ampliación del código fuente de la anterior solo para facilitar su lectura. Bueno
empecemos, en la línea (1) vemos el modelo que la vista recibe como un parámetro, cuyo valor será
establecido por la vista que la invoca, como podemos ver en la Figura 43. Las líneas (3 y 5) solo son la
apertura y el cierre de un tag “div” que cumple la función de darle un formato al texto del título, en este
caso poniéndolo en negrita. En la línea (4) el marcador “@Model” será reemplazado por el valor del título,
cada vez que utilicemos este marcador “Razor” se encargará de reemplazarlo, de esta manera si hubiésemos
escrito 3 marcadores el titulo aparecería tres veces, es esta sintaxis la que le hará que nuestra página web
deje de ser estática.

Figura 65

17.2. Desarrollo de la vista parcial “_Menu”: Lo que sigue es una guía paso a paso,
esperemos no tropezar, que nos llevara al desarrollo de la vista “_Menu”.

Presionando el botón derecho del mouse sobre el directorio indicado en la siguiente figura, aparecerán los
menús contextuales, seleccionamos la opción “View…”.

Figura 66

39
Escrito por: Horacio Aldo Tore

El nombre de la vista será “_Menu” y la marcamos como parcial, hacemos clic sobre el botón de “Add”.

Figura 67

40
Escrito por: Horacio Aldo Tore

El entorno de desarrollo o IDE (Integrated Development Environment), crea el archivo “_Menu.cshtml”. Al


ser una vista parcial no añade código HTML alguno dentro del archivo, ya que esta será incrustada como
parte de otra vista que si poseerá este código “<html>, <head> y <body>”.

Figura 68

La vista parcial se crea dentro del directorio “Shared” para poder compartirla con facilidad con otras vistas,
ya que varias la utilizaran.

Figura 69

41
Escrito por: Horacio Aldo Tore

A diferencia de la vista parcial “_Titulo”, la vista “_Menu” no posee un modelo como parámetro, ya que no
posee “@model”, compare el código de la Figura 70 contra el de la Figura 65. Las líneas (1 y 7) solo señalan
la apertura y cierre de un tag de HTML llamado “div” que cumple la función de establecer un color de fondo,
lo valioso a destacar son las líneas (2 y 4) formadas por el “helper” “Html.ActionLink” que terminara
escribiente un tag “<a>” en el navegador.

Figura 70

La línea (2) generaría el siguiente código HTML:


Figura 71
<a href="/Candidato/Insert">Nuevo candidato</a>

Podemos deducir donde irán a parar los parámetros del “helper” “Html.ActionLink”:
Figura 72

42
Escrito por: Horacio Aldo Tore

La Figura 59 nos dará una visión de la apariencia de la vista parcial “_Menu” en la interfaz del usuario.

Al hacer clic sobre el enlace navegamos a la siguiente página web, ver Figura 73, en la cual podemos
observar cómo se conforma la URL según el patrón de diseño “Convention over configuration (CoC)”.

Figura 73

Esta invocación se realizará mediante [HttpGet] o protocolo HTTP método GET o en otras palabras por lo que
se conoce más simplemente como Query string. Es por esta razón que el “Action method” ”Insert” esta
adornado con el atributo “[HttpGet]” como se muestra en la siguiente figura:

Figura 74

43
Escrito por: Horacio Aldo Tore

Si no existe el atributo “[HttpGet]” sobre un “Action method”, se toma por defecto este atributo, de modo
que funcionalmente es lo mismo el código de la Figura 74 que el de la Figura 75:

Figura 75

La línea (4) de la Figura 70, posee un análisis similar al ya realizado para la línea (2) de esa figura, ya que
utiliza el mismo “helper” “Html.ActionLink”, razón por la cual no realizaremos el mismo.

18. Validaciones: Para seguir con este ejemplo práctico utilizaremos dos tipos de validaciones a saber, las
validaciones por atributos y validaciones del lado servidor utilizando el método “AddModelError”.
18.1. Validaciones por atributos: ASP.NET MVC nos brinda una manera estándar y simple de
realizar validaciones, es mediante el decorado con atributos sobre las propiedades del modelo que
deseamos validar. La Figura 76, muestra el agregado del atributo “[Required]” sobre la propiedad
“Nombre” en la línea (13), esto causará una validación a nivel cliente y servidor, exigiendo que dicha
propiedad no pueda estar en blanco o en otras palabras sea de ingreso obligatorio por parte del usuario.
Notemos que estos atributos recién se encontraran disponible en nuestro desarrollo cuando agreguemos el
namespace “System.ComponentModel.DataAnnotations” que se ve en la línea (5) ya que la clase
“RequiredAttribute” depende de este.

Figura 76

La propiedad “PorcentajeDeVotos” también es de ingreso obligatorio así que podríamos decorarla con un
atributo “[Required]”, pero no lo aremos para mantener la simplicidad del ejemplo y así lograr una
comprensión más sencilla.

44
Escrito por: Horacio Aldo Tore

Hasta aquí el código que se agregó en el modelo del lado del servidor, ahora debemos agregar código del
lado cliente para que esta validación tenga efecto, de lo contrario no sucederá.

En la línea (21) de la Figura 77, se ha utilizado el helper “Html.ValidationMessageFor” que será el


responsable de mostrar un mensaje de error al usuario de la aplicación he impedir el envío del formulario vía
HTTP método POST al servidor. Ahora para que este helper funcione es necesario agregar los archivos que
incluyen el código Java Script de las líneas (1, 2 y 3) ya que “Html.ValidationMessageFor” los utiliza,
invocando sus funciones de validación.

Figura 77

La Figura 78, muestra el mensaje de error arrojado por el “Html.ValidationMessageFor” al momento que el
usuario intenta grabar los datos del candidato sin completar propiedad “Nombre” cunado hace clic sobre el
botón “Grabar”.

Figura 78

45
Escrito por: Horacio Aldo Tore

En caso de querer mostrar un resumen que contenga todas las validaciones que han fallado, podemos
hacerlo agregando al código de la vista “Edit.cshtml” la línea (32), tal como se muestra en la Figura 79.

Figura 79

Al ejecutar la aplicación e intentar persistir un candidato sin nombre o con nombre en blanco, la misma nos
mostrará al pie de la página el resumen de las validaciones que fallaron, tal como se ve en la figura siguiente.

Figura 80

Otro punto a destacar es el uso de los comentarios con sintaxis “Razor”, utilizados en el código de la Figura
79, línea (31). Estos son más eficientes, más beneficioso que los comentarios HTML ya que serán quitados al
46
Escrito por: Horacio Aldo Tore

momento de resolver la vista del lado servidor y no viajarán al browser cliente con todo lo que esto conlleva,
menor cantidad de bytes a transmitir vía HTTP y menor tiempo de interpretación o (parseo) por parte del
browser cliente. La Figura 81 muestra una versión de la vista “Edit.cshtml” en la cual se reemplazó el
comentario con sintaxis “Razor” por uno con sintaxis “HTML”, puede comparar la Figura 81 contra la Figura
79 y ver la diferencia expresada en la línea (31).

Figura 81

Ahora supongamos que no estamos de acuerdo con el mensaje que es establecido por defecto por el helper
“Html.ValidationMessageFor”, podemos reemplazar el mismo por otro más adecuado, lo que se conoce
como personalizado. La Figura 82 muestra en la línea (13) que se ha establecido el texto que emos elegido
para mostrar al cliente y que es pasado como parámetro al atributo “Required”.

Figura 82

La Figura 83, muestra el nuevo mensaje personalizado que ha reemplazado al anterior y que ahora aparece
en nuestra aplicación.

47
Escrito por: Horacio Aldo Tore

Figura 83

Desarrollaremos una generalización, ya que existen dos propiedades del modelo que son requeridas el
“Nombre” y el “PorcentajeDeVotos”, tal como se ve en la Figura 84. El parámetro “ErrorMessage” (13 y 16)
funciona como una plantilla con un marcado llamado “{0}” el cual será completado con el nombre de la
propiedad sobre la que actúa, al momento de generar la vista.

Figura 84

En la siguiente figura podemos ver al trio más utilizado de helpers, “Html.LabelFor”, “Html.EditorFor” y
“Html.ValidationMessageFor”, de esta manera podemos mostrar la etiqueta, el control más adecuado y la
validación, respectivamente, de cada propiedad.

Figura 85

48
Escrito por: Horacio Aldo Tore

De esta forma tendremos la siguiente interfaz de usuario cuando no se completan los campos requeridos y el
usuario intenta persistirlos.

Figura 86

Si bien las validaciones en el cliente son necesarias por razones de usabilidad a nivel usuario ya que las
mismas son resueltas sin necesidad de enviar y recibir información al servidor, cosa que sería muy lenta. No
podemos confiar en ellas debido a que la aplicación cliente podría ser suplantada por otra que no realice
validación alguna. Por lo cual debemos añadir código del lado servidor, código inaccesible para el cliente y
por ende confiable, en otras palabras, añadir una validación en el “Action method” “Edit” que recibe la
información vía HttpPost.

El código de la Figura 87, tiene una precondición rustica (80), poco sofisticada pero que funciona y valida que
el modelo este correcto, en cuyo caso permite la ejecución del código que se encuentra debajo, dejando
persistir o eliminar un registro. Para esto utilizamos la propiedad “ModelState” del controlador que nos
indica mediante su propiedad “IsValid” si existe al algún error. Las “DataAnnotations” son validadas y tenidas
en cuenta por la propiedad “IsValid”, como demostraremos más adelante con un experimento.

Figura 87

49
Escrito por: Horacio Aldo Tore

Realicemos el siguiente experimento, comentemos las líneas que incluyen los scripts de JavaScript para
anular las validaciones del lado cliente, tal como se muestra en la Figura 88.

Figura 88

Ahora la aplicación llegará al “Action method” “Edit” vía HttpPost aunque dejemos en blanco el campo
“Nombre”, como se muestra en la Figura 89.

Figura 89

Luego que el usuaria realice un clic sobre el botón “Grabar” de la Figura 89, se lanzara la excepción que se ve
en la Figura 90, observemos que el valor de la propiedad “IsValid” se encuentra en falso ya que el modelo no
es válido debido a que la validación de campo requerido sobre el nombre no es exitosa.

50
Escrito por: Horacio Aldo Tore

Figura 90

Realizando una inspección rápida sobre la propiedad “ModelState” tal como muestra la Figura 91, podemos
observar que “IsValid” vale falso ya que la propiedad “Nombre” tiene un error de validación cuyo mensaje es
“El Nombre no puede estar en blanco.”, este error se debe al atributo “[Required(ErrorMessage = "El {0}
no puede estar en blanco.")]” que se encuentra sobre la propiedad “Nombre” del modelo, tal como
podemos observar en la Figura 84 línea (13). Razón por la cual concluimos que la propiedad “ModelState”
tiene en cuanta “DataAnnotations”.

Figura 91

51
Escrito por: Horacio Aldo Tore

Podemos validar el rango numérico permitido para un porcentaje, tomando como mínimo el 0 (cero) y como
máximo el 100, esta comprobación la realizamos con otro atributo llamado “Range” que decore la propiedad
“PorcentajeDeVotos” tal como muestra la siguiente figura en la línea (17).

Figura 92

Podemos observar el la Figura 92, el parámetro “ErrorMessage” (17) que no es otra cosa mas que una
plantilla con tres marcadores, “{0}” será remplazado por el nombre de la propiedad que está decorando,
“{1}” será remplazado por 0 (cero) (primer parámetro de Range) y “{2}” será remplazado por 100 (segundo
parámetro de Range).

Figura 93

En la Figura 93, podemos ver la interfaz de usuario generada por la vista “Edit.cshtml”, en la cual están
reemplazados los valores de los marcadores “{0}” “{1}” y “{2}” que se encuentran en el código de la Figura
92 línea (17).

18.2. Validaciones utilizando el método AddModelError: Existen validaciones que no


pueden ser realizadas en el cliente, es este el caso que ocurre al insertar un nuevo candidato, su
“PorcentajeDeVotos” sumado a los ya existentes nunca puede ser mayor a 100, y esto se debe validad
sumando los porcentajes existentes en la base de datos, en otras palabras, del lado servidor. Por ejemplo, si
ya existen dos candidatos persistidos en la base de datos, uno con 30% y otro con 60%, al momento de
ingresar un tercero no puede poseer un porcentaje superior a 10% ya que la suma no puede ser superior al
100%.

52
Escrito por: Horacio Aldo Tore

ASP.NET MVC nos brinda una forma de validar esto adicionando un error a la colección de errores de una
clave (Key) existente de la propiedad “ModelState”, utilizando el método “AddModelError”, tal como se ve
en la Figura 94 línea (44).

Utilizamos Entity Framework y Language Integrated Query (LINQ) para calcular la suma de los porcentajes
existentes (38) par adicionarle el porcentaje del nuevo candidato (43) y validar que la suma no supere 100, si
esto ocurre adicionamos un error sobre la clave “PorcentajeDeVotos” con el mensaje “Los porcentajes
superan el 100%” (44), este mensaje será mostrado en la vista por los helpers
“Html.ValidationMessageFor(m => m.PorcentajeDeVotos)” y “Html.ValidationSummary()”, dando como
resultado la interfaz de usuario que se muestra en la Figura 95.

Es de destacar que el método “InsertPrecondition” (33), si bien retorna “void”, modifica la propiedad
“ModelState” (44) cosa que es inspeccionada en la línea siguiente a la invocación (26) para determinar si
hacer el insert en la base de datos (27). El desarrollo no es del todo correcto o purista ya que hay que
conocer el método “InsertPrecondition” a caja blanca debido a que su firma no define ningún valor de
retorno, pero se tomó esta salvedad para favorecer la simplicidad y beneficiar la transmisión de la idea.

Figura 94

La siguiente figura, Figura 95, muestra como queda la interfaz de usuario cuando hay un error por superar
100% en la suma de los porcentajes, los existentes más el nuevo.

Figura 95
53
Escrito por: Horacio Aldo Tore

La Figura 96, muestra el código “Razor” de la vista “Insert.cshtml” a la que se le han agregado los helpers de
validación, señalados con una flecha y responsables de los mensajes que se ven la interfaz de usuario de la
Figura 95.

Figura 96

19. Conclusión: ASP.NET MVC de Microsoft se basa en el conocido patrón MVC para logra la separación de
responsabilidades en: un modelo abstracto e independiente, una vista encargada de la interfaz de usuario y un
controlador responsable en escuchar y ejecutar peticiones vía HTTP, para luego pasar el modelo resultante de
nuevo a la vista.
Otro aspecto para destacar y que no está definido en el patrón MVC, pero si en ASP.NET MVC de Microsoft, es la
estandarización de nombres de directorios y de archivos que constituyen el andamiaje (Scaffolding) que nos
brinda una organización común para todos los desarrollos mediante el patrón “Convention over configuration
(CoC)”.
Por último, los helpers nos brindan una manera sencilla de mostrar y validar propiedades del modelo.

54
Escrito por: Horacio Aldo Tore

20. Referencias:
Se termino de escribir el: 30 de enero de 2019
Autor: Horacio Aldo Tore
Manual del framework ASP.NET MVC, en idioma https://desarrolloweb.com/manuales/framework-
castellano escrito por Eduard Tomàs: asp-net-mvc.html

What are ActionResults?, en idioma ingles escrito https://www.exceptionnotfound.net/asp-net-


por Matthew Jones: mvc-demystified-actionresults/

55

También podría gustarte