Razor Helpers

Para aquellos que venimos trabajando desde el inicio con ASP.NET MVC recordaran que con la versión de MVC 3 aparecía Razor, el view engine que nos permitía armar vistas mas simples escribiendo menos caracteres 🙂

Hoy vamos a hablar de una característica de Razor que muchas veces se nos pasa por alto, pero que les puede resultar muy útil. Se trata de la sintaxis @helper que nos permite escribir métodos auxiliares re-utilizables en las vistas.

Trabajemos en un simple ejemplo para apreciar la utilidad de esta sintaxis. Supongamos que tenemos una lista que muestra información sobre personas y en una de las columnas es necesario mostrar su dirección postal. Para el caso en que no existiera esta información hay que mostrar la frase “No se cuenta con la dirección postal“.

Como ya se imaginan, esto requiere escribir una simple porción de lógica en la vista que muestre el texto que corresponda dada una condición determinada. Para esto vamos a crear un método auxiliar con la sintaxis @helper que vamos a llamar MostrarDireccionPostal:

Definiendo un Razor Helper

Definiendo un Razor Helper

Sencillo, no?… Seguramente se estarán preguntando cómo podemos hacer para reutilizar esté método en otras vistas de mi aplicación sin necesidad de re-escribir el @helper en cada una de estas vistas. Para esto simplemente debemos mover nuestro método a un archivo con extensión .cshtml o .vbhtml dentro del directorio “/App_Code” (en mi caso lo voy a llamar SebysHelpers.cshtml):

SebysHelpers Template

SebysHelpers Template

Tengan en cuenta que el template SebysHelpers.cshtml se compila bajo la clase SebysHelpers la cual me va a proveer del método estático MostrarDireccionPostal (dentro del template podemos poner cuantos métodos queramos). Hecho esto finalmente resta modificar la vista para invocar el método correspondiente:

Invocando al método dentro del template.

Invocando al método del template.

Como podemos ver el uso de la sintaxis @helper nos permite encapsular lógica del renderizado de las vistas en métodos auxiliares que podemos compartir entre deferentes vistas de una manera muy sencilla y generando código mas legible y mantenible.

Espero que les sea de mucha utilidad.

Abrazos!

Anuncios

ASP.NET MVC : Entendiendo ResponseRedirect

Quienes desarrollamos en algún momento en ASP.NET Webform no necesitábamos tener conocimientos web de bajo nivel ya que los mismos eran abstraídos por el mismo framework. Esto se debía a que ASP.NET, en ese entonces, había sido pensado para atraer a los desarrolladores de aplicaciones de escritorio que se resistían pasar al desarrollo de aplicaciones web. Por lo tanto, la estrategia de MS fue seguir con esa misma filosofía.

En el momento en que uno hace el pase a ASP.NET MVC – cosa que recomiendo a todo desarrollador web de .NET 🙂 – tiene la necesidad de conocer más en profundidad estas cuestiones (HTTP, HTML, CSS…), ya que es parte de la naturaleza del framework y facilita enormemente el desarrollo sobre el mismo.

Como mencione anteriormente, una de las cuestiones web son los protocolos y  hace un tiempo atrás participé de la excelente VAN que presento Leonardo Micheloni sobre HTTP (llamada “HTTP y las ruedas de la web“) donde uno de los tema que toco fueron los distintos códigos de estado que provee este protocolo.

Para quienes no conozcan demasiado de este tema cuando uno hace una petición por medio de una URL se inicia una transacción desde el cliente que termina con una respuesta del servidor que generalmente viene compuesta por el recurso solicitado (sea un HTML, XML…). Uno de los datos que viajan en el encabezado de la respuesta es el código de estado (de los cuales los más conocidos son 200 OK o 404 NOT FOUND).

Estos códigos de estado se encuentran agrupados según su función y uno de esos grupos corresponden a las Redirecciones : 3xx.

Todo esto me hizo pensar en como funcionaba realmente el método RedirectToAction que nos provee la clase Controller de ASP.NET MVC.  Y mis sospecha – no demasiadas brillantes – eran ciertas, la solicitud a una vista que utiliza RedirectToAction retorna HTTP Code Status 302.

Antes de continuar, veamos un poco más en profundidad, de que se trata el código 302 viendo una definición de Wikipedia:

Este es el código de redirección más popular, pero también un ejemplo de las prácticas de la industria contradiciendo el estándar. La especificación HTTP/1.0 (RFC 1945) requería que el cliente realizara una redirección temporal (la frase descriptiva original fue “Moved Temporarily”), pero los navegadores populares lo implementaron como 303 See Other. Por tanto, HTTP/1.1 añadió códigos de estado 303 y 307 para eliminar la ambigüedad entre ambos comportamientos. Sin embargo, la mayoría de aplicaciones web y bibliotecas de desarrollo aún utilizan el código de respuesta 302 como si fuera el 303.

Luego de esta larga introducción, vayamos al grano y definamos dos vistas, la primera la llamaremos Index y la segunda Final. Lo que hará la primer vista será simplemente redireccionar a la segunda:

1: public class HomeController : Controller
2: {
3:     public ActionResult Index()
4:     {
5:         return RedirectToAction("Final");
6:     }
7:
8:     public ActionResult Final()
9:     {
10:         return View();
11:     }
12: }

Ejecutemos y analicemos la respuesta del servidor:

Respuesta HTTP

Respuesta HTTP

Vemos que la petición GET a la URL “http://localhost…/Index” retorna el código 302 Found, y seguido se hace una nueva petición a “http://localhost…/Final” que finalmente es devuelta exitosamente (retornando el código 2oo OK).

Para saber donde tiene que hacer la redirección, uno de los datos que viajan en el encabezado de la respuesta es Location el cual contiene dicha información:

Encabezado de la respuesta HTTP

Encabezado de la respuesta HTTP

Es importante que entendamos como funcionan estas cuestiones, que si bien son simples, uno muchas veces las desconoce pensando que todo es resuelto “magicamente” por el framework.

Espero que les haya sido de utilidad.

ASP.NET MVC 3 y Structure Map

Como ya hemos hablado en otros post, una de las características que nos permiten mejorar el código de nuestros desarrollos es la utilización de patrones de diseño. Uno de esos patrones es la Inyección de Dependencias que consiste en suministrar objetos a una clase en lugar de ser la propia clase quien cree el objeto.

En este post voy a mostrarles un framework llamado Structure Map que nos permite aplicar este patrón en nuestros proyectos .NET y la forma de integrarlo al soporte de IoC que provee ASP.NET MVC 3.

Structure Map es un framework para .NET que nos permite trabajar con Inyección de Dependencias e Inversión de Control.

El primer paso sera agregar las referencias a la librería de Structure Map. Para ello vamos a instalarlas utilizando Nuget:

Agregando la librería Structure Map

Agregando la librería Structure Map

Es importante recordar que la pieza central respecto al soporte de IoC que provee ASP.NET MVC 3 es la interfaz IDependencyResolver que nos permite “conectar” distintos motores de IoC con tan solo implementarla en una clase y luego registrarla.

En nuestro ejemplo vamos a crear nuestro propio Dependecy Resolver que va a ser manejado con Structure Map. Para ellos vamos a crear la clase StructureMapDependencyResolver que, como dijimos anteriormente, implementará IDependencyResolver:

1: public class StructureMapDependencyResolver : IDependencyResolver
2: {
3:     private IContainer container;
4:
5:     public StructureMapDependencyResolver(IContainer container)
6:     {
7:         this.container = container;
8:     }
9:
10:     public object GetService(Type serviceType)
11:     {
12:         if (serviceType.IsAbstract || serviceType.IsInterface)
13:         {
14:             return this.container.TryGetInstance(serviceType);
15:         }
16:         else
17:         {
18:             return this.container.GetInstance(serviceType);
19:         }
20:     }
21:
22:     public IEnumerable<object> GetServices(Type serviceType)
23:     {
24:         return this.container.GetAllInstances<object>()
25:             .Where(s => s.GetType() == serviceType);
26:     }
27: }

Lo que hicimos aquí fue implementar los siguiente métodos:

En ambos métodos hemos utilizado el contedor IContainer (que nos provee la librería Structure Map) cuya finalidad es la de registrar y resolver las dependencias que hayamos definido.

Bien, ahora vamos a crear una interfaz bien simple, la cual denominaremos IMessage:
1: public interface IMessage
2: {
3:     string GetMessage();
4: }

Y dos implementaciones bien sencillas de la misma, la primera la llamaremos HelloMessage:

1: public class HelloMessage : IMessage
2: {
3:     public string GetMessage()
4:     {
5:         return "Buenos días!" ;
6:     }
7: }

Y la segunda ByeMessage:

1: public class ByeMessage : IMessage
2: {
3:     public string GetMessage()
4:     {
5:         return "Hasta mañana!" ;
6:     }
7: }

Llego el momento de registrar a nuestro “resolvedor(?) de dependencias”  🙂 y para ello debemos agregar las siguientes lineas en el archivo global.asax:

1: public class MvcApplication : System.Web.HttpApplication
2: {
3:     public static void RegisterGlobalFilters(GlobalFilterCollection filters)
4:     {
5:         filters.Add(new HandleErrorAttribute());
6:     }
7:
8:     public static void RegisterRoutes(RouteCollection routes)
9:     {
10:         routes.IgnoreRoute("{resource}.axd/{*pathInfo}" );
11:
12:         routes.MapRoute(
13:             "Default", // Route name
14:             "{controller}/{action}/{id}", // URL with parameters
15:             new { controller = "Home" , action = "Index" } 
16:         );
17:
18:     }
19:
20:     protected void Application_Start()
21:     {
22:         AreaRegistration .RegisterAllAreas();
23:
24:         RegisterGlobalFilters(GlobalFilters.Filters);
25:         RegisterRoutes(RouteTable.Routes);
26:
27:         InitializeContainer();
28:     }
29:
30:     public void InitializeContainer()
31:     {
32:         var c = InitContainer();
33:         DependencyResolver.SetResolver(new StructureMapDependencyResolver(c));
34:     }
35:
36:     private static IContainer InitContainer()
37:     {
38:         var container = new Container();
39:
40:         container.Configure(s => s.For<IMessage>().Use<HelloMessage>());
41:
42:         return container;
43:     }
44: }

Dentro del método Application_Start() invocamos un nuevo método llamado InitializeContainer() en el cual vamos a registrar StructureMapDependencyResolver como el encargado de resolver las dependencias. Previamente a este paso hemos creamos el método InitContainer() en el cual hemos creado un objeto Container al cual le fuimos configurando el mapeo entre interfaces y clases que sera utilizado para poder resolver las dependencias (en el ejemplo solo es uno y es el de IMessage).

Es hora de crear el controlador HomeController cuyo constructor recibirá como parámetro un IMessage el cual será “inyectado” cada vez que sea instanciado (de lo cual ya no debemos preocuparnos gracias a IDependencyResolver). También vamos a definir un método de acción Index:

1: public class HomeController : Controller
2: {
3:     private IMessage MessageService { get ; set ; }
4:
5:     public HomeController(IMessage service)
6:     {
7:         this .MessageService = service;
8:     }
9:
10:     public ActionResult Index()
11:     {
12:         ViewBag.Message = MessageService.GetMessage();
13:
14:         return View();
15:     }
16: }

Ejecutamos y veremos que el servicio instancia es el que hemos definido al momento de crear el contenedor, en este caso HelloMessage:

Resultado obtenido de HelloMessage

Resultado obtenido de HelloMessage

Ahora modificamos el contenedor para instanciar el servicio ByeMessage en la interfaces IMessage:

1: private static IContainer InitContainer()
2: {
3:     var container = new Container();
4:
5:     container.Configure(s => s.For<IMessage>().Use<ByeMessage>());
6:
7:     return container;
8: }

Ejecutamos y verificamos que se invoco el servicio que definimos:

Resultado obtenido con ByeMessage

Resultado obtenido con ByeMessage

De más esta decir, que esto simplifica y mejora el código de nuestros desarrollos, ya que en el caso de que debamos modificar la referencias a nuestros servicios, y si estos mantienen el contrato, solo debemos modificar una sola línea de nuestro proyecto, y es el mapeo entre interfaz y clase que hemos configurado en el contenedor de dependencias.

Quienes quieran descargar el proyecto pueden hacerlo desde acá: MvcAndStructureMap.rar.

Espero que les sea de utilidad.

Entity Framework 4.1 CF y Lazy Load

Para finalizar esta serie de post sobre Entity Framework 4.1 CF, vamos a hablar de una nueva caracteristica: soporte de Lazy Load (Carga Diferida).

Comencemos con una definición general de Lazy Load para que nos demos una mejor idea de que estamos hablando:

El Lazy Loading es un patron de diseño util y simple que se basa en ir cargando los distintos componentes de una clase cuando los vamos usando.

Ahora vamos a ver como trabaja este patrón de diseño dentro del framework EF CF 4.1.

En la definición anterior explica que Lazy Loading tiene como finalidad ir cargando los distintos componentes de una clase a medida que lo vamos usando. Esos componentes en EF se representan por medio de las llamadas propiedades de navegación, las cuales nos proporcionan una forma de navegar de una asociación o relación entre dos tipos de entidades, retornando una referencia a un objeto (si la relación es de cero a uno o uno a uno) o una colección (si la relación es de uno a muchos).

En nuestro ejemplo las propiedades de navegación son: Eventos que pertenece a la clase Agenda y Agenda que pertenece a la clase Evento:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }
1:     public class Evento
2:     {
3:         public int EventoId { get ; set ; }
4:         public int AgendaID { get ; set ; }
5:         public DateTime Fecha { get ; set ; }
6:         public string Comentario { get ; set ; }
7:
8:         public virtual Agenda Agenda { get ; set ; }
9:     }

Notece que por convención dichas propiedades son marcadas como virtual (si no las marcamos de esta forma, no podremos aprovechar las ventajas de LazyLoad).

Antes de escribir nuestra primer linea de código, quiero comentarles que Lazy Loading en EF 4 viene habilitada por default. Esto no es del todo apropiado, sobre todo cuando el volumen de datos es demasiado grande o en el caso de que solo quiera recuperar, por ejemplo, un listado de agendas, donde no me interesa conocer todos sus eventos asociados. Para evitar esto, vamos a decirle al DbContext que por defecto esta característica – LazyLoadingEnabled – venga des-habilitada. Entonces modificamos el constructor de nuestro DatosContext:

1: public class DatosContext : DbContext
2: {
3:     public DbSet<Agenda> Agendas { get; set; }
4:     public DbSet<Evento> Eventos { get; set; }
5:
6:     public DatosContext() : base("name=DatosContext") 
7:     {
8:         this.Configuration.LazyLoadingEnabled = false; 
9:     }
10: }

Ahora sí, ya tenemos nuestro entorno listo, comencemos!

Lo primero que debemos hacer es crear y grabar una agenda y luego asignarle un par de eventos (de esta forma podremos visualizar mejor los ejemplos). Una forma simple de realizar esto es sobre-escribir el método Seed() de la clase DatosInitializer tal como lo explicamos en el primer post de esta serie.

Ya conocemos la forma en que se relacionan nuestras entidades, por lo tanto vamos a hacer uso del método Include() que nos proporciona la clase DbQuery. También podemos hacer uso de la extensión Include() provisto por DbExtensions (para este caso recordemos importar System.Data.Entity).

Include() es el método que nos permite obtener de una consulta el set completo de datos de una entidad y de todas sus relaciones.

Generalmente para recuperar la lista de alguna entidad (en nuestro caso de agendas) escribimos la siguiente consulta:

1: public ActionResult Index()
2: {
3:     var agendas = datos.Agendas.ToList();
4:
5:     return View(agendas);
6: }

Sin embargo, esto no nos recupera la lista de eventos asociados a cada agenda (siempre y cuando hayamos desactivado la característica de Lazy Loading). Inspeccionando la primer agenda de la lista podemos afirmar esto:

Inspeccionando objetos obtenidos con EF4.1 sin LazyLoad

Inspeccionando objetos obtenidos con EF4.1 sin LazyLoad

Para poder recuperar la agenda y sus eventos asociados debemos hacer uso del método Include() donde le pasaremos como parametro la propiedad de navegación de la cual queremos obtener los datos:

1: public ActionResult Index()
2: {
3:     var agendas = datos.Agendas.Include("Eventos").ToList();
4:
5:     return View(agendas);
6: }

Ahora vemos los mismos objetos obtenidos con LazyLoad:

Inspeccionando objetos obtenidos con EF4.1 con LazyLoad

Inspeccionando objetos obtenidos con EF4.1 con LazyLoad

Como observamos, se han recuperado también los Eventos de la agenda.

Para finalizar veamos algunos ejemplos más de lo que podemos hacer con EF y Lazy Load:

1:// Recupero todas las relaciones entre agenda y eventos utilizando DbQuery.
2:// La asociación se especifica por medio de un string.
3:var ag = datos.Agendas.Include("Eventos").ToList();
4:
5:// Recupero todas las relaciones entre agenda y eventos utilizando DbExtensions
6:// La asociación se especifica por medio de una expresion lambda.
7:var ae = datos.Agendas.Include(e => e.Eventos).ToList();
8:
9:// Recupero una agenda creada en el día de hoy y sus eventos.
10:var a1 = datos.Agendas
11:          .Where(a => a.FechaCreacion == DateTime .Now)
12:          .Include(e => e.Eventos)
13:          .FirstOrDefault();

Espero que le haya sido de utilidad.

Entity Framework 4 CF y DataAnnotations

Vamos a continuar con el post anterior sobre EF 4.1 CF y en este caso ver un poco más en profunidad como se integra con el mecanismo de validación provisto por ASP.NET MVC denominado DataAnnotations.

Lo primero sera recordar como teniamos definida la clase Agenda y como EF contruyo la tabla Agenda a paritr de dicho modelo:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }

El esquema de la tabla generada es el siguiente:

Esquema de la tabla Agenda

Esquema de la tabla Agenda

Como vemos en las propiedades de cada columna, el campo Propietario acepta valores nulos, y es lógico segun lo que definimos en nuestro modelo. En cambio el campo FechaCreacion no lo es, ya que el tipo de datos sobre el cual se armo es DateTime y el mismo no admite valores nulos.

Ahora bien, supongamos que por algun motivo necesitamos que el propietario se deba cargar de forma obligatoria, si bien este modelo sigue sirviendo, nada nos asegura que este dato siempre sea grabado en la base de datos. Entonces que mejor forma de asegurarnos esto que deshabilitando la propiedad Allow Nulls en la tabla. Pero si solo lo hacemos en la base de datos, puede darse el caso que alguna instancia de nuestro modelo venga con dicho atributo nulo, y al momento de grabar tengamos uno de dos problemas: o una excepción porque el campo es nulo, o se graba un espacio en blanco en dicho registro.

Por lo tanto, la mejor opción es aplicar ambas validaciones: a nivel DB y a nivel modeloASP.NET MVC provee una interesantisima libreria que nos permite aplicar reglas de validación sobre nuestro modelos, estas reglas luego podemos replicarlas en cada controlador y vista en donde sea utilizado el modelo.

Esta librería es DataAnnotation y las normas que podemos definir se aplican como atributos de las clases, generalmente a nivel de las propiedades. En nuestro caso, y sin complicarla demasiado, vamos a marcar la propiedad Propietario como requerida (Required):

1: using System.ComponentModel.DataAnnotations;
2:
3: namespace MvcAndEF.Models
4: {
5:     public class Agenda
6:     {
7:         public int AgendaId { get ; set ; }
8:         [Required]
9:         public string Propietario { get ; set ; }
10:         public DateTime FechaCreacion { get ; set ; }
11:
12:         public virtual ICollection<Evento> Eventos { get ; set ; }
13:     }
14: }

Lo mas interesante de esto, es que DataAnnotations se integra perfectamente con EF4 y este último al detectar una propiedad como requerida, modifica las estructura de la base de datos deshabilitando en ese campo la propiedad Allow Nulls, evitando de esta forma que se ingresen valores nulos en dicho campo, y asi asegurarnos que ese dato siempre estara disponible en el registro.

Nuevo esquema de la tabla Agenda

Nuevo esquema de la tabla Agenda

Además ya tendremos nuestra validación funcionando en el formulario web:

Validación web

Validación web

Espero que les haya sido de utilidad!

Introducción Entity Framework 4.1 Code Firts

La versión 3.5 SP1 del framework .NET nos proveia de una biblioteca ORM llamada Entity Framework. Esta primera versión recibió varias criticas por parte de los desarrolladores, las cuales por suerte fueron escuchadas por el equipo de .NET. Es por este motivo que junto a la salida de .NET 4 apareció una versión mejorada llamada Entity Framework 4.1.

Entre las mejoras que se incluyen en esta nueva versión se encuentran: el manejo de clases POCO, soporte para Lazy Load, mejor calidad en las querys SQL generadas, mayor compatibilidad con Linq entre otras más.

En este post vamos a trabajar con una nueva caracteristica de EF llamada Code Firts (cuya traducción valida prodía ser “Partiendo del código“) y cuyo punto fuerte es que partiendo de nuestras clases del dominio ya podemos crear nuestro modelo ORM. Todo esto sin preocuparnos por la creación de la base de datos, el mapeo entre las entidades y la DB, los archivos XML o editores y todas las configuraciones afines.

Pero vayamos por parte, antes de comenzar con un ejemplo, vamos a crear un proyecto ASP.NET MVC 3 y agregar las referencias a esta librería. Para poder trabajar con EF 4.1 Code First antes vamos a tener que instalar el componente EFCodeFirst y podemos hacerlo de una manera muy sencilla utilizando Nuget (en la pestaña online\all buscamos dicho componente e instalamos).

Instalando EF4.1 desde Nuget

Instalando EF4.1 desde Nuget

Finalizada nuestra instalación se nos abrirá un archivo ReadMe con algunos comentarios sobre el producto y se habrán agregado a la solución los assemblies correspondientes.

El segundo paso sera crear las entidades del modelo, en este ejemplo vamos a trabajar con dos entidades muy simples, la primera representara una agenda y la segunda eventos de la misma. Estas clases a crear son objetos simples denominados POCO en el ambiente .NET (es importante que estas clases POCO respeten algunas convenciones que no son para nada complejas y que nos permitirán trabajar con EF).

Es el turno de definir las clases que compondran nuestro modelo:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }

1:     public class Evento
2:     {
3:         public int EventoId { get ; set ; }
4:         public int AgendaID { get ; set ; }
5:         public DateTime Fecha { get ; set ; }
6:         public string Comentario { get ; set ; }
7:
8:         public virtual Agenda Agenda { get ; set ; }
9:     }

Algo interesante a comentar de estas entidades es que las propiedades definidas como virtual corresponden a propiedades de navegación, y son aquellas que se pueden cargar en “diferido” (en otro post vamos a ver de que se trata esto).

El segundo paso será crear un contexto que nos permita realizar operaciones CRUD sobre nuestras instancias de Agenda y Evento. Para esto vamos a crear una clase llamada DatosContext que derive de DbContext y que contendra dos propiedades publicas (una por cada entidad del modelo que hemos creado) que seran del tipo DbSet<T>:

1: using System.Data.Entity;
2:
3: namespace MvcAndEF.Models
4: {
5:     public class DatosConext : DbContext
6:     {
7:         public DbSet<Agenda> Agendas { get ; set ; }
8:         public DbSet<Evento> Eventos { get ; set ; }
9:     }
10: }

Como ya se habran dado cuenta, estas librerias pertenecen a System.Data.Entity y son provistas por EF4.1. Las clases DbContext y DbSet nos permitiran realizar las operaciones relacionadas con el acceso a los datos.

A pesar de todo esto aún no hemos creamos la base de datos y mucho menos un mapeo con la misma, tampoco hemos utilizamos diseñadores y mucho menos realizamos configuraciones. Sin embargo ya estamos listo para trabajar! 🙂

Cómo es posible esto?… la respuesta es bastante sencilla, EF 4.1 Code First esta pensado para trabajar por convenciones en lugar de configuraciones (es por eso que al crear nuestras clases POCO tuvimos en cuenta ciertas consideraciones). El resto es historia conocida: cada clase se corresponderá con una tabla, cada propiedad una columna de la misma y cada instancia de dichas clases representará un registro en la base de datos.

Para ver en funcionamiento nuestro contexto, vamos a trabajar sobre un nuevo controlador llamado AgendaController y en las diferentes acciones armaremos consultas para persistir y recuperar los datos de nuestro modelo:

1: using System.Linq;
2: using System.Web.Mvc;
3: using MvcAndEF.Models;
4:
5: namespace MvcAndEF.Controllers
6: {
7:     public class AgendaController : Controller
8:     {
9:         DatosContext datos = new DatosContext();
10:
11:         public ActionResult Index()
12:         {
13:             var agendas = from a in datos.Agendas
14:                           select a;
15:
16:             return View(agendas.ToList());
17:         }
18:
19:         public ActionResult Create()
20:         {
21:             return View();
22:         }
23:
24:         [HttpPost]
25:         public ActionResult Create(Agenda model)
26:         {
27:             if (ModelState.IsValid)
28:             {
29:                 datos.Agendas.Add(model);
30:                 datos.SaveChanges();
31:
32:                 return RedirectToAction("Index");
33:             }
34:
35:             return View(model);
36:         }
37:
38:         public ActionResult Edit(int id)
39:         {
40:             var agenda = datos.Agendas.Single(a => a.AgendaId == id);
41:             return View(agenda);
42:         }
43:
44:         [HttpPost]
45:         public ActionResult Edit(Agenda model)
46:         {
47:             if(ModelState.IsValid)
48:             {
49:                 var agenda = datos.Agendas.Single
50:                             (a => a.AgendaId == model.AgendaId);
51:                 agenda.Propietario = model.Propietario;
52:                 agenda.FechaCreacion = model.FechaCreacion;
53:
54:                 datos.SaveChanges();
55:
56:                 return RedirectToAction("Index");
57:             }
58:
59:             return View(model);
60:         }
61:     }
62: }

En cada uno de los métodos de acción podemos observar ejemplos de las consultas básicas: selección, inserción y actualización de una entidad. Lo siguiente será crear cada una de las vistas para dichos métodos (lo cual se los dejo de tarea).

Ya tenemos todo listo y aún seguimos sin noticias de la base de datos 🙂 . Pues bien, es hora de que hablemos un poco de ella.

Existen dos estrategias a seguir para definir la DB: la primera es crear el esquema de la base de datos con alguna herramienta, como por ejemplo SQL Management Studio. La segunda permitir que EF 4.1 la genere por nosotros!

Por supuesto que vamos a utilizar la última opción y para eso sera necesario que en el archivo de configuración web.config agreguemos una nueva cadena de conexión para nuestra futura base de datos (esta entrada deberá tener el mismo nombre que la clase DbContext que hemos creado, para nuestro ejemplo DatosContext):

1:  <connectionStrings>
2:  <add name="DatosContext"
3:  connectionString= "Data Source=|DataDirectory|Datos.sdf"
4:  providerName= "System.Data.SqlServerCe.4.0 "/>
5:  </connectionStrings>


Nota: en nuestro caso vamos a usar como proveedor SQL Server Compact Edition 4.0 pero podriamos utilizar SQL Sever o MySql con solo modificar dicho parámetro dentro de la cadena de conexión.

Ahora simplemente ejecutamos y ya podremos crear nuestras primeras entidades:

Nuestra app corriendo

Nuestra app corriendo

Entramos al alta de Agendas:

Formulario de alta

Formulario de alta

Y creamos nuestra primer entidad:

Agregando nuestra primer entidad

Agregando nuestra primer entidad

Como podemos ver, los datos se guardaron sin necesidad de tener que crear manualmente la DB. Validemos esto abriendo el explorador de soluciones:

Base de datos creada

Base de datos creada

EF para generar automaticamente nuestra base de datos buscara dentro del archivo de configuración una cadena de conexión que tenga el mismo nombre que la clase heredada de DbContext y utilizando esta información creará el archivo correspondiente:

Modelo sobre el cual EF se basa para crear la DB

Modelo sobre el cual EF se basa para crear la DB

Podremos inspeccionar la base de datos desde el explorador de servidores (para poder visualizar la DB creada con SQL Server CE 2.0 deberemos instalar previamente el Visual Studio 2010 SP1):

Estructura de la DB creada

Estructura de la DB creada

La tabla EdmMetadata contiene información acerca de la estructura de los objetos del modelo utilizados al momento de crear la base de datos.

Para finalizar, supongamos que tenemos que modificar el modelo, deberiamos redefinir nuestra DB cierto? por defecto EF4.1 al detectar una modificación en el modelo no modifica la estructura de nuestra DB, solamente el contenido de la tabla EdmMetadata.

Para solucionar esto tenemos distintas maneras de sincronizar el modelo con la base de datos: una es hacerlo de forma manual, modificando la estructura de la tabla/s afectadas. Sin embargo existe una manera mucho mas simple para el desarrollador y es por medio del método DropCreateDatabaseIfModelChanges que viene incluida en la libería de EF4.1.

Para esto debemos agregar la siguiente línea en el método Application_Start() del archivo global.asax:

1: Database.SetInitializer<DatosContext>
2:     (new DropCreateDatabaseIfModelChanges<DatosContext>());

Como bien lo dice su nombre, este mecanismo lo que hace es eliminar y volver a crear la base de datos, por lo que todos los registros previamente grabados se perderan. Sin embargo, una forma de solucionar este problema es insertar automáticamente registros cada vez que se genere la base de datos, y la forma de hacerlo es creando una nueva clase “inicializadora” (habré inventado una nueva palabra?) que herede de DropCreateDatabaseIfModelChanges<T> donde T sera DatosContext y en la cual vamos a sobre-escribir el método Seed():

1: public class DatosInitializer : 
2:              DropCreateDatabaseIfModelChanges <DatosContext >
3: {
4:     protected override void Seed(DatosContext context)
5:     {
6:         Agenda agenda = new Agenda ()
7:         {
8:             Propietario = "Sebis" ,
9:             FechaCreacion = DateTime .Now
10:         };
11:
12:         context.Agendas.Add(agenda);
13:     }
14: }


Ahora solo resta modificar la línea que hemos escrito anteriormente dentro de global.asax para que cada vez que se vuelva a generar la base de datos, se inserten dichos registros:

1: Database.SetInitializer(new DatosInitializer ());


Resumiendo, EF 4.1 CF me parece muy recomendable para utilizar en desarrollos de pequeña escala, y ademas facilita  enormemente ciertas tareas al desarrollador, como por ejemplo evitar muchas de las configuraciones que siempre molestan a la hora de ponerse a programar.

En la proxima entrada vamos a ver como podemos integrar los validadores de ASP.NET MVC (Data Anottations) con EF4.1.

Espero que les sea de utilidad!

ASP.NET MVC 3: Client-Side Validation Enabled por Default

En las versiones anteriores de MVC, era necesario invocar al método Html.EnableClientValidation() desde una vista para habilitar la validación del lado del cliente. Por ejemplo debíamos escribir algo similar a esto en la vista:

1:<script type="text/javascript" src="/Scripts/MicrosoftAjax.js"/> 
2:<script type="text/javascript" src="/Scripts/MicrosoftMvcValidation.js"/> 
3:<h2> Create</h2> 
4: <% Html.EnableClientValidation();  %>
5: <% using  (Html.BeginForm()) { %>  
6:   <%=  Html.ValidationSummary(true )  %>  
7:
8:       <fieldset> 
9:           <legend> Campos</legend> 
10:           <div  class="editor-label"> 
11:                <%=  Html.LabelFor(model => model.Nombre)  %>  
12:           </div> 
13:           <div  class="editor-field"> 
14:                <%=  Html.TextBoxFor(model => model.Nombre)  %>  
15:                <%=  Html.ValidationMessageFor(model => model.Nombre)  %>  
16:           </div> 
17:           <p> 
18:               <input  type="submit"  value="Create"  /> 
19:           </p> 
20:       </fieldset> 
21:<% }  %>

Lo que teníamos que tener en cuenta era la invocación al método EnableClientValidation y las referencias a los scripts MicrosoftAjax,js MicrosoftMvcValidation.js (este último nos permitía validar las propiedades de un modelo que tenían asignados atributos de validación DataAnnotations desde el lado del cliente).

En MVC 3 este paso ya no es necesario ya que la validación del lado del cliente está habilitada de forma predeterminada. Podemos habilitarla o deshabilitarla modificando la siguiente entrada en nuestro web.config:

1:<appSettings> 
2:  <add key= "ClientValidationEnabled " value= "true "/>  
3:  <add key= "UnobtrusiveJavaScriptEnabled " value= "true "/>  
4:</appSettings>

La key ClientValidationEnabled en true nos permite trabajar con la validación del lado del cliente de manera predetermina. La key UnobtrusiveJavaScriptEnable en true nos evitara mezclar el código javascript dentro del HTML, tal como se explico en este post.

También es necesario agregar en la vista la referencia a la librería de jQuery jquery.validate.js. Esta librería es la que trabajara en conjunto con los atributos DataAnnotation que hayamos definido en el modelo de la vista para poder realizar las validaciones client-side.

Veamos todo con un ejemplo muy simple, lo primero que vamos hacer es crear un modelo reducido para la entidad Cliente y al mismo vamos a definirle el atributo Nombre como requerido:

1: using  System;
2: using  System.Collections.Generic;
3: using  System.Linq;
4: using  System.Web;
5: using  System.ComponentModel.DataAnnotations;
6:
7: namespace Mvc3.Models
8: {
9:     public class ClienteModel 
10:     {
11:         [Required(ErrorMessage= "El nombre es obligatorio.")]
12:         public string Nombre { get; set; }
13:
14:         public int? Edad { get; set; }
15:     }
16: }

En el controlador vamos a definir los métodos de acción de creación del cliente:

1: namespace Mvc3.Controllers
2: {
3:     public class ClienteController : Controller 
4:     {
5:         public ActionResult Create()
6:         {
7:            return View();
8:         }
9:
10:         [HttpPost]
11:         public ActionResult Create(ClienteModel model)
12:         {
13:             if(ModelState.IsValid)
14:             {
15:                 return View();
16:             }
17:
18:             return View(model);
19:         }
20:     }
21: }

Finalmente vamos a crear la vista, hacemos click derecho sobre el método de acción Create, y en el menú elegimos “Add View…“. En la ventana que se nos abre elegimos que sea de tipado fuerte y elegimos nuestro modelo previamente creado: ClienteModel. También vamos a seleccionar que sea un formulario de creación y para quinenes hayan definido una master page la seccionan. En nuestro caso vamos a usar como ViewEngine Razor.

Configurando la vista

Configurando la vista

Van  a ver que al crear la vista esta ya incluye las referencias a los script necesarios para la validación del lado del cliente:

1:  @model   Mvc3.Models.ClienteModel 
2:  @{
3:     ViewBag.Title = "Create";
4:     Layout = "~/Views/Shared/_Layout.cshtml";
5:  }
6:
7: <h2>Create</h2> 
8:
9: <script src="  @Url.Content("~/Scripts/jquery.validate.min.js")"  
10:         type="text/javascript"></script> 
11: <script src="  @Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"  
12:         type="text/javascript"></script> 
13:
14:  @ using Html.BeginForm()) {
15:      @ Html.ValidationSummary(true )
16:     <fieldset> 
17:         <legend>ClienteModel</legend> 
18:
19:         <div class="editor-label"> 
20:              @ Html.LabelFor(model => model.Nombre)
21:         </div> 
22:         <div class="editor-field"> 
23:              @ Html.EditorFor(model => model.Nombre)
24:              @ Html.ValidationMessageFor(model => model.Nombre)
25:         </div> 
26:
27:         <div class="editor-label"> 
28:              @ Html.LabelFor(model => model.Edad)
29:         </div> 
30:         <p> 
31:             <input type="submit"  value="Create"  /> 
32:         </p> 
33:     </fieldset> 
34: }
35: <div> 
36:      @ Html.ActionLink("Back to List" , "Index" )
37: </div> 

Ya tenemos todo configurado, ejecutamos y podremos chequear que definitivamente las validaciones se hacen del lado del cliente.

Validación del formulario

Validación del formulario

Si queremos validar que esto es del todo correcto, deshabilitamos en el web.config la entrada ClientValidationEnabled y volvemos a ejecutar. Efectivamente vamos a ver que en este caso la validación se hace desde el servidor provocando el submit del formulario.

Espero que les haya sido de utilidad!