Presentación de FluentViewModel

Hola nuevamente. No me pude esperar, así que decidí presentarles mi proyecto para ASP.NET MVC: FluentViewModel. Espero subirlo a GitHub en un futuro cercano (es decir, no muy lejano, jejeje…), para que esté disponible para todo el mundo, y quien lo quiera mejorar pueda hacerlo.

¿Qué es FluentViewModel?

FluentViewModel es una interfaz fluida para definir modelos de vista en ASP.NET MVC usando C#, construida sobre FluentValidation.

FluentViewModel permite mapear las propiedades de un modelo existente a plantillas de editores de formulario y vistas, aprovechando las ventajas de las clases genéricas, notación lambda y la funcionalidad de autocompletar de Visual Studio, para facilitar a los programadores la creación de modelos de vista.

Por otra parte, FluentViewModel hace uso de las funcionalidades de FluentValidation para definir las validaciones necesarias a realizarse para los objetos.

¿Cómo funciona FluentViewModel? (a grosso modo)

Creo que la mejor forma de explicar cómo funciona, es con un ejemplo:

Supóngase que se tiene el siguiente modelo:

Modelo
En clases (definición simple, no la de Entity Framework):

public class TipoProducto
{
    public int IdTipoProducto { set; get; }
    public string Nombre { set; get; }
    public IEnumerable Productos { set; get; }
}

public class Producto
{
 public int IdProducto { set; get; }
 public string Nombre { set; get; }
 public string Sku { set; get; }
 public string Upc { set; get; }
 public DateTime FechaActivacion { set; get; }
 public TipoProducto Tipo { set; get; }
}

Para definir el formulario de creación y edición de productos desde FluentViewModel bastaría hacerlo de la siguiente forma:

using System;
using System.Collections.Generic;
using System.Linq;
using G2RF.Web.Mvc.FluentViewModel.Mapping;
using G2RF.Web.Mvc.FluentViewModel.Form.Buttons;
using G2RF.Web.Mvc.FluentViewModel.Form.Validation;
using FluentValidation;
using System.Text.RegularExpressions;
using System.Web.Mvc;

namespace EjemploMVC.Models
{
    public class ProductoVM : ViewModelMap
    {
        public ProductoVM()
        {
            //Mapear propiedades

            //- IdProducto como oculto
            MapProperty(x => x.IdProducto)
                .Edit(y => y.AsHidden());

            //- Nombre como caja de texto
            MapProperty(x => x.Nombre)
                .WithLabel("Nombre")
                .Edit(y => y.AsTextBox().Length(20))
                .ValidateRule(z =>
                    z.NotEmpty().WithMessage("El nombre es obligatorio.")
                        .Length(1,20).WithMessage("La longitud máxima permitida para el nombre es de 20 caracteres."),
                    ValidatorPositionEnum.Summary);

            //- Tipo de producto como lista desplegable
            MapProperty(x => x.Tipo)
                .WithLabel("Tipo de producto")
                .Edit(y =>
                    y.AsRadioButtonGroup()
                        .UsingTextFormat("{0}")
                        .UsingAsDisplayField(a => a.Nombre)
                        .UsingAsValueField(a => a.IdTipoProducto)
                        .UsingGetOptionsMethod(() =>
                            StructureMap.ObjectFactory.GetInstance().TipoProducto.ToList()));

            //- Sku como caja de texto
            MapProperty(x => x.Sku)
                .WithLabel("SKU")
                .Edit(y => y.AsTextBox().Length(6))
                .ValidateRule(z =>
                    z.NotEmpty().WithMessage("El SKU del producto es obligatorio")
                        .GreaterThanOrEqualTo(1).WithMessage("El SKU debe ser mayor que 1"),
                    ValidatorPositionEnum.Summary);

            //- Upc como caja de texto
            MapProperty(x => x.Upc)
                .WithLabel("UPC")
                .Edit(y => y.AsTextBox().Length(13))
                .ValidateRule(z =>
                    z.NotEmpty().WithMessage("El UPC es obligatorio.")
                        .Must(a => a != null && Regex.Match(a, "[0-9]{13}").Success)
                        .WithMessage("El código UPC debe tener una longitud de 13 caracteres numéricos"),
                    ValidatorPositionEnum.Summary);

            //- Fecha de activación como calendario
            MapProperty(x => x.FechaActivacion)
                .WithLabel("Fecha de activación")
                .Edit(y => y.AsDate())
                .ValidateRule(z =>
                    z.Must(f => f > DateTime.Now)
                        .WithMessage("La fecha de activación debe ser posterior al día de hoy."));

            //Agregar botones
            AddButton(new FormButton() { Text = "Guardar", Name = "guardar", Behavior = ButtonBehaviorEnum.Submit });

            //Estableciendo método de formulario
            FormSubmit(FormMethod.Post);

            //Estableciendo clase CSS
            UseFormCssClass("product_form");

            //Mostrar sumario de validación
            ShowValidationSummary();
        }
    }
}

Luego, en la vista, para desplegar todo el formulario (la mejor parte, jajaja…):

<h2>Editar producto</h2>
<%=Html.EditorForModel() %>

Y finalmente, el formulario:

FormularioCabe mencionar que el FluentViewModel no trae por defecto los controles web para los distintos tipos de datos, sino que hace uso de las plantillas de editores que se definen bajo el folder Views/Shared/EditorTemplates. En otras palabras, hay buenas y malas noticias: la buena noticia es que el usuario puede definir las plantillas de editores a su gusto, y sobreescribirlas en cada área; la mala es que el usuario debe crear las plantillas.

Para este ejemplo, se crearon estas plantillas haciendo uso de los controles Developer Express para MVC.

En entradas futuras explicaré cómo surgió la idea de crear FluentViewModel, y cómo utilizarlo (para ese punto, espero ya haber subido alguna versión a GitHub).

Feliz día.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s