MVC
MVC
MVC
NET I: Empezando
[forCode] > Lenguaje > .NET > MVC .NET I: Empezando
Que es?
MVC son las siglas de Model View Controller. Bsicamente es un patrn desarrollado para escritorio en los 70 para el
desarrollo de escritorio, pero donde se saco provecho es en los ltimos aos en entorno web. Elmodel obtiene los datos,
la vista muestra el cdigo html/js y el controller es el que enlaza todo. Con este patrn el usuario ya no accede
directamente a una pgina web, si no que accede al controller, que obtiene los datos del model si lo necesita y enva
esos datos a la vista.
Este patrn no es exclusivo de .NET, lo podemos encontrar en varios lenguajes.
Ventajas
Las ventajas de MVC son bastantes, el cdigo se divide bastante por lo que es ms fcil de mantener y hacer nuevos
desarrollos, al acceder al controller, y que este nos de el cdigo resultado, tambin ofrecemos una capa de
ofuscacin
Y en .NET conseguimas mas ventajas, tenemos los helpers de razor, si enviamos datos en json desde la vista
al controller, se puede traducir automticamente (tenemos que crear un objeto con esas propiedades y listo),
el intellisense de VS, el IDE en general de VS,
Empezamos
Primero vamos a ver un ejemplo, del tpico hola mundo y despus ir explicando que nos podemos encontrar en este
proyecto. Crearemos un proyecto de MCV Empty(Lo ir explicando con MVC 4) y que tenga las plantillas de razor.
Controller
Crearemos un Controller que se llame Compra con una funcin que se llame ListaCompra, esta devolver una un listado
de objetos en JSON con la compra. Para hacerlo, tenemos que darle botn derecho sobreControllers y le
damos Add/Controller, como nombre le ponemos CompraController ( siempre tiene que llevar la coletilla de Controller) y
le indicamos en el Template la opcin de Empty controller.
Aqu podemos ver que solo hay una funcin que se llama Index, esta se ejecutar al llamar al Controllersin parmetros.
Lo dejamos tal cual.
View
Crearemos una View para asociarlo con el Controller de Compra. Desplegamos el directorio Views del proyecto y le
damos (con el botn derecho) a Agregar/Nueva Carpeta y le llamamos Compra (como elController, tiene que ser as), y
ahora le damos con el botn derecho a Agregar/View y le llamamos Index(como la funcin del Controller, y se tiene que
llamar igual :) ) y debajo del titulo de Index, ponemos un prrafo con Hola mundo.
Resultado
Ahora ejecutamos el proyecto y nos saltar un error, es normal, en la url agregamos el nombre delController pero sin la
coletilla de Controller, en nuestro caso Compra y veremos que nos carga la pgina. As ya tenemos el Hola
mundo ahora vamos a explicar un poco como esta distribuido el proyecto.
El proyecto
Bsicamente, tendremos libros que estarn relacionados con los autores, editoriales, genero (romance, blico, misterio,
), Saga ( si pertenece a una saga de libros)
Se que habrn 50.000 gritones de pginas o software, pero es lo que se me ocurri :). Lo he simplificado para que de
momento no haya demasiado.
Iba a hacer una gestin de gastos/ingresos con previsiones, etc, pero se hizo grande y sera denso (y extenso), como
para introducirnos en MVC.
Controller View
Para empezar, veremos como pasar datos entre el controller y la view, para ello creamos un nuevo proyecto de MVC
Empty (con el motor de Razor). Yo le he llamado Libreria. Ahora no utilizaremos acceso a BDD, retornaremos datos a
pincho.
Para pasar datos a la View, veremos 3 formas: el ViewBag, ViewData y el ViewModel.
ViewData
El ViewData es un objeto del tipo diccionario (clave valor) que no requiere instanciarse. Para verlo, crearemos
un controller llamado LibrosController con la opcin de Empty. Por defecto nos crea una funcin, el Index pero
aadimos una nueva funcin donde rellenemos este parmetro. Nos tendra que quedar as:
?
1 public ActionResult Datos()
2 {
3 ViewData["Clave"] = "valor";
4 return View();
}
5
Creamos la vista asociada al controller, para ello aadimos un directorio a Views con el nombre delcontroller (en nuestro
caso Libros) y luego la view (Datos.cshtml) y lo dejamos as:
?
1 <h2>Datos</h2>
3 @ViewData["Clave"]
Si ejecutamos nos tendra que salir por pantalla valor (para ver esta pagina sera url/controller/funcion, en mi
caso http://localhost:2121/libros/datos
Ahora en controller vamos a poner que nos devuelva un listado de libros listado, para ello dejamos la funcin de datos
as:
?
1 ViewData["Clave"] = new List< Libro>() {
4 };
return View();
5
*NOTA* Para crear un listado podemos hacer var x = List< Object>(); y despus un .Add(new Object()); o utilizar esta
anotacin, que es parecida al formato de JSON. Es lo mismo y sobre gustos colores :). **
Si ejecutamos, veremos que no nos imprime lo que queremos, esto es porque recibe un Object y tenemos
que castearlo y recorrerlo. Modificamos la View para que muestre lo mismo que en el otro ejemplo:
?
1 <h2>Datos</h2>
2
3
<table>
4 <thead><tr><td>Nombre</td><td>Descripcion</td></tr></thead>
5 <tbody>
7 {
8 <tr><td>@lib.Nombre</td><td>@lib.Descripcion</td></tr>
}
9
</tbody>
10
</table>
11
El problema es que tienes que pasarle la clave como una cadena de texto y si te equivocas, no te enteras hasta que te
salta el error. Aparte, tienes que castear el valor en la mayora de casos.
Si ejecutamos esto, nos mostrara una tabla con los libros.
ViewBag
El Viewbag es muy parecido a el ViewData, es un objeto tipo clave valor pero se le asigna de manera diferente.
Para verlo generamos otra funcin que quede as:
?
1
public ActionResult Cartera()
2 {
};
6
return View();
7
}
8
2
<table>
3
<thead><tr><td>Nombre</td><td>Descripcion</td></tr></thead>
4
5 <tbody>
6 @foreach (var lib in ViewBag.lstLibros)
7 {
8 <tr><td>@lib.Nombre</td><td>@lib.Descripcion</td></tr>
9 }
</tbody>
10
</table>
11
Como podemos ver, en el ViewBag tenemos la propiedad lstLibros, la que hemos aadido en el controller, pero no
requiere casteo. En ese aspecto encuentro que esta solucin es mas acertada que el ViewData, pero tiene el mismo
problema, no te ayuda el intellisense de VS y cuando accedes a la propiedad delViewBag te puedes equivocar.
Ejecutamos y vemos el mismo resultado que en el otro ejemplo (para verlo, en mi caso sera
http://localhost:2121/libros/cartera)
ViewModel
Para pasar los datos a la vista, crearemos una clase vaca en el directorio Models y le llamaremos Libros. Le aadimos
como propiedades el Nombre y la Descripcion. Nos tendra que quedar as:
?
1 public class Libro
2 {
}
5
Creamos una nueva funcin para devolver los libros, tal que:
?
1 public ActionResult OModelo()
{
2
var lstLibros = new List<Libro>() {
3
new Libro() { Nombre = "Templario", Descripcion = "Novela de templari
4
new Libro() {Nombre ="Legion", Descripcion = "Novela de romanos"}
5
};
6
7
return View(lstLibros);
8
}
9
Con esto nos devolvera un listado de libros, para verlo crearemos la view de
estecontroller(Views/Libros/OModelo.cshtml ). Modificamos la View para que quede as:
?
1
@model List<NOMBRE_PROYECTO.Models.Libro>
2
3
<h2>Lista de libros</h2>
4 <table>
5 <thead><tr><td>Nombre</td><td>Descripcion</td></tr></thead>
6 <tbody>
8 {
<tr><td>@lib.Nombre</td><td>@lib.Descripcion</td></tr>
9
}
10
</tbody>
11
</table>
12
En la primera linea le indicamos que el modelo es nuestra lista deViewModel de Libro. Despus hemos creado
una minitabla para que nos muestre el contenido del listado, para ello hemos usado Razor, el@foreach lo que hace es
recorrer el listado y los va aadiendo a la tabla.
Ejecutamos la aplicacin (en mi caso http://localhost:2121/libros/OModelo) y tendramos que ver una tabla con
los 2 libros.
A mi me gusta ms esta ltima, porque en VS aprovechas el intellisense y como veremos en el siguiente artculo, tiene
mas cosas buenas. Eso no quiere decir que no las puedas combinar, puedes devolver unViewModel y, aparte, rellenar
un ViewBag con los parmetros de configuracin (por ejemplo).
MVC .NET III: Razor
[forCode] > Lenguaje > .NET > MVC .NET III: Razor
Situemonos
En .NET salio ASP que tena controles de servidor. Eran del estilo < asp:label /> y se podan combinar con controles
de HTML. Por debajo pona una clase de vb/c# para controlar los eventos de estos controles. Esto era lento y haba
eventos que refrescaban la pgina y te hacan perder la informacin. Despus saliASP MVC donde no hay ningn
control de ASP propio, solo html o cdigo que genera html. Este cdigo que genera HTML se usa con el < %:, pero tiene
el mismo inconveniente que PHP, cada vez que lo quieres utilizar tienes que abrir y cerrar tags. Despus
salio Razor con MVC 3 y la sintaxis cambi bastante. ConRazor tienes que poner @ para escribir cdigo y el ya deduce
cuando acaba. Aparte de no tener que estar abriendo y cerrando cdigo, tiene la ventaja de que queda ms limpio el
cdigo.
La sintaxis es, bsicamente, de 2 formas:
@Parametro/instruccion (ejemplo: @Model.Nombre), ponemos una arroba y lo que queremos que salga por pantalla
@{}, esto es para hacer trozos de cdigo que no devuelven texto HTML. Por ejemplo, cuando creamos
una View tenemos lo siguiente:
?
1 @{
2 ViewBag.Title = "Libro";
3 }
Esto introduce en el ViewBag una propiedad con un valor, pero no lo muestra por pantalla.
[spoiler intro=Nota]Instrucciones como el foreach para recorrer una lista y mostrarla, serian de
tipo@Parametro/instruccion porque esperamos que devuelva cdigo HTML:
?
1
<table>
2 <thead><tr><td>Nombre</td><td>Descripcion</td></tr></thead>
3 <tbody>
5 {
6 <tr><td>@lib.Nombre</td><td>@lib.Descripcion</td></tr>
}
7
</tbody>
8
</table>
9
Algunos ejemplos
No voy a explicar cada una de las mejoras, pero podemos ver unos ejempos de uso bsicos y conforme vayamos
avanzando (y necesitando ms chicha) iremos viendo mas ejemplos :).
Para mostrar una collection utilizaremos un foreach, vamos a seguir con el ejemplo de los libros ( el objeto libro tiene 2
propiedades: Nombre y Descripcion) y quedar tal que:
?
1
@model List<NOMBRE_PROYECTO.Models.Libro>
2
<table>
3 <thead><tr><td>Nombre</td><td>Descripcion</td></tr></thead>
4 <tbody>
6 {
7 <tr><td>@lib.Nombre</td><td>@lib.Descripcion</td></tr>
}
8
</tbody>
9
</table>
10
La funcin del controller nos devuelve un List< NOMBRE_PROYECTO.Models.Libro>, le indicamos aRazor que ese ser
nuestro ViewModel (para que est tipado).
Siempre, en el bloque de cdigo del foreach (entre {}) tiene que empezar con un < para que no interprete que es
cdigo Razor. Si ponemos directamente texto, tendremos que ponerle un < span> o < text>.
Aparte del foreach, tienes el for, if, . solo lo he usado de ejemplo.
Helpers
Son trozos de cdigo que te ayudan (como su propio nombre indica :)) a hacer acciones o mostrar elementos que
con html quizs no te baste. Por ejemplo si desplegas un proyecto y tienes una redireccion, seguramente no coincidir la
url.
Redirecciones
Ahora, en lugar de utilizar el tpico < a href, podemos utilizar Razor. Esto tiene un porqu y es porque una vez desplegas
la aplicacin puede variar la URL, y con Razor te lo hace solo.
Para ello tenemos que utilizarlo as (Normalmente):
?
1 @Html.ActionLink(texto, funcion/accion)
Elementos de HTML
Tambin tenemos elementos (tipo textbox, botones, ) en Razor para ayudarnos, como lo siguiente:
?
1 @Html.TextBox(NombreBotn, Valor, AtributosHTML)
Valor y AtributosHTML son opcionales. Los atributos se los puedes pasar en un diccionario clave-valor o con un objeto.
Por ejemplo:
?
1 @Html.TextBox("txtNombre", "Introduce un nombre", new { @class = "miClase" })
Os habreis fijado que @Html.TextBox hay 2, esto porque el @Html.TextBox es el TextBox normal y
el@Html.TextBoxFor() es en el que le indicamos una propiedad del modelo para que lo asocie:
?
1 @Html.TextBoxFor(LinQ)
?
1 @Html.TextBoxFor(m => m.Nombre)
Pero teniendo una collection (por ejemplo la de libros, que tiene 2 propiedades: Nombre y Descripcion) tendramos que
hacerlo as:
?
@for (var i = 0; i <Model.Count(); i++ )
1
{
2
<div>
3
<h2>@Html.TextBoxFor(m => m.ElementAt(i).Nombre)
4
@Html.TextBoxFor(m => m.ElementAt(i).Descripcion) </h2>
5
</div>
6 }
Hay varios helpers como display para mostrar,BeginForm y EndForm para abrir y cerrar un formulario
(lostags), checkbox, dropdownlist, Si queris ver que elementos podis utilizar solo tenis que poner@HTML. y
el intelisense de VS te mostrar las posibilidades.
Aparte de poder ensear el ViewModel, puedes hacer funciones para utilizarlo como tus helpers.
Me explico supongamos que tenemos una grid con una de las columnas que el texto ( en segn que filas ) es
demasiado grande y provoca que algunas filas puedan estar en 2 lineas. Podramos crear una funcin que nos
imprimiese el texto con
Creamos la funcin por el principio de la pgina:
?
1
@helper recorta(string input, int length)
2 {
4 @input
5 } else {
}
7
}
8
Y la pgina:
?
1 <table>
2
<thead><tr><td>Nombre</td><td>Descripcion</td></tr></thead>
3 <tbody>
5 {
7 }
</tbody>
8
</table>
9
De esta manera recortara los textos y los hara presentables. Y esto es todo por hoy!! En el siguiente veremos como
hacer un alta de libros, pasando un ViewModel del Controller a la vista y mostrndolo conRazor
MVC IV: Formulario de alta
[forCode] > Lenguaje > .NET > MVC IV: Formulario de alta
Antes de empezar, comentar que todos los artculos del tutorial aparecern aqu
ViewModel
El ViewModel estar en el directorio de Models y yo lo llamare Libro(recordad que es una clase normal). Tendr los
campos de Id, NumeroSaga, Nombre, Descripcion y Fecha.
?
1
public class Libro
2 {
4 public int NumeroSaga { get; set; } // Esto es por si pertenece a una saga de libros.
4 }
6 [HttpPost]
{
8
lib.Nombre += " test"; // esto es para que veais que se modifica, si no parece que no h
9
return View(lib); // aqu pondremos un BreakPoint para ver lo que obtiene.
10
}
11
He puesto que las 2 devuelvan la vista para ver en el formulario que se modifica. Por defecto, las funciones
del controller son para peticiones de tipo Get y si tenemos 2 funciones con el mismo nombre, no sabe a por cual ir (no
funciona la sobrecarga ). Lo que podemos hacer es enviar la peticin por POST, por eso la segunda funcin tiene la
cabecera de [HttpPost].
View
En la View es donde tendremos el formulario. Podremos todos los parmetros del ViewModel con
losHelpers de Razor (La View estar en Views/Libros/AltaLibros.cshtml):
?
1 @model Libreria.Models.Libro //le decimos el ViewModel
2
<h2>AltaLibros< /h2>
3
4
@using (Html.BeginForm("AltaLibros", "Libros", FormMethod.Post)) //etiqueta form que va al co
5
{
6
<label>Numero Saga< /label>@Html.TextBoxFor(m => m.NumeroSaga) <br />
7
<label>Nombre< /label>@Html.TextBoxFor(m => m.Nombre)<br />
8
<label>Descripcion< /label>@Html.TextBoxFor(m => m.Descripcion)<br />
9
<label>Fecha< /label>@Html.TextBoxFor(m => m.Fecha)<br />
10
<button type="submit" >Alta</button>
11
12
}
13
Si ejecutamos, parecer que no hay cambios, pero esta funcionando bien. Si os habis fijado en elBreakPoint, el
objeto lib tiene los parmetros que le hemos puesto, pero para verlo mejor, vamos a modificar la vista para que cargue
los datos.
?
1
@using (Html.BeginForm("AltaLibros", "Libros", FormMethod.Post)) //etiqueta form que va al co
2 {
8
}
9
{
2
<label>Numero Saga</label>@Html.TextBoxFor(m => m.NumeroSaga) <br />
3
<label>Nombre</label>@Html.TextBoxFor(m => m.Nombre, new { Value = Model.Nombre })<br />
4
<label>Descripcion</label>@Html.TextBoxFor(m => m.Descripcion)<br />
5
<label>Fecha</label>@Html.TextBoxFor(m => m.Fecha)<br />
6
<button type="submit" >Alta</button>
7
}
8
Podemos editar la llamada de Ajax que hace para que vaya a una direccin en concreto (con js).
Con esto tendramos un funcionamiento sencillo de un formulario con razor y MVC. EN el siguiente veremos Entity
Framework y Code first.
Entity Framework: Ejecucin de Scripts
[forCode] > Lenguaje > .NET > Entity Framework: Ejecucin de Scripts
Veamos como
Lo primero que intentamos siempre es realizar nuestro propio parseador de ficheros para realizar la tarea que queremos.
Y as fue :)
Aunque trs algun error y sin poder depurar mucho la migration de pruebas, realizando unabsqueda encontramos una
solucin muy parecida a la que queriamos. Y trs acceder al cdigo en github y realizar unas modificaciones quedo esto:
?
1 public abstract class DbMigrationExtended : DbMigration
2 {
{
11
"GO", // Migrations doesn't support GO
12
"/*", // Migrations might not support comments
13
"--", // Migrations might not support comments
14
"print" // Migrations might not support print
15
};
16
17
var sql = string.Join(" ", sqlLines.Where(line => !string.IsNullOrEmpty(line) &
18
19 Sql(sql, suppressTransaction);
20 }
21 }
22
Adaptaciones Propias
Como podis ver la complejidad es obtener el directorio de ejecucin en el momento de lanzar el update-
database desde la consola, adems de ignorar ciertas lineas e instrucciones sql por seguridad.
Adems hemos realizado una modificacin para que por convencin nuestros scripts siempre estn ubicadas en una
misma carpeta y tengan la misma extensin, en caso contrario fallar; pero nos viene bien para ir cogiendo buenas
prcticas de forma que nuestro proyecto tendra esta estructura:
Al final podemos construir una migration lanzando el tpico add-migration en la consola y una vez creada heredar de
nuestra nueva clase, si es necesario, y agregar la nueva instruccin para invocar ficheros.
Migration de Ejemplo
?
1 public partial class SampleMigration : DbMigrationExtended
2 {
7
public override void Down()
8
{
9
10
}
11 }
12
Conclusiones
Si se te ocurre alguna funcionalidad que no provee por defecto .NET, buscalo antes de realizar tu propia funcionalidad,
puesto que seguro que antes se le ha ocurrido ya a alguien, hay versiones mejores que la tuya o por lo menos ms
probadas.