Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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;
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
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
7. ¿Por dónde empezar, por M, por V o por C?: Al iniciar con MVC, nos hacemos la siguiente
pregunta
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.
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.
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.
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
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
26
Escrito por: Horacio Aldo Tore
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.
Figura 46
29
Escrito por: Horacio Aldo Tore
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
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
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
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
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á.
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).
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
55