lunes, 21 de junio de 2010
Hace unos días experimentábamos con controladores capaces de implementar automáticamente la lógica de acciones cuya misión era únicamente retornar la vista por defecto.
Así, partíamos de un controlador como el siguiente:
Y veíamos cómo simplemente heredando de la clase
Está claro que utilizando como base la clase
Si el único código que vamos a tener en un controlador es la definición de la propia clase, quizás podamos hacer algo para evitar incluso tener que codificar eso, ¿no? De la misma forma que hicimos con las acciones, seguro que podríamos crear un controlador por defecto para procesar las peticiones entrantes para las que no podamos encontrar un controlador específico.
Dentro de la factoría de controladores, el método GetControllerType() es utilizado por el framework para localizar el tipo (la clase) de controlador en función del nombre obtenido desde los parámetros de ruta. De hecho, este mismo método es el que utilizamos hace más de un año para saltarnos a la torera la convención de nombrado de controladores del framework.
De hecho, si heredamos de la factoría de controladores por defecto, basta con sobrescribir este método
Ya lo último que necesitamos es indicar al framework la factoría de controladores que debe utilizar, la clase
Y con eso, hemos terminado. A partir de ese momento, todas las peticiones cuyo controlador sea imposible localizar según el procedimiento estándar, serán procesadas por el controlador automático AutoController, que buscará para cada acción una vista y la retornará mágicamente al usuario.
Así, una petición de tipo
Publicado en: Variable not found.
Así, partíamos de un controlador como el siguiente:
public class HomeController: Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Company()
{
return View();
}
public ActionResult Services()
{
return View();
}
public ActionResult Contact()
{
return View();
}
}
Y veíamos cómo simplemente heredando de la clase
AutoController
que definíamos en el mismo post, podíamos omitir la implementación de las acciones anteriores, consiguiendo un código mucho más compacto:public class HomeController: AutoController
{
}
Está claro que utilizando como base la clase
AutoController
hemos ahorrado mucha codificación, pero, perezosos como somos, seguro que todavía estamos escribiendo más de la cuenta. Si el único código que vamos a tener en un controlador es la definición de la propia clase, quizás podamos hacer algo para evitar incluso tener que codificar eso, ¿no? De la misma forma que hicimos con las acciones, seguro que podríamos crear un controlador por defecto para procesar las peticiones entrantes para las que no podamos encontrar un controlador específico.
¡A por la factoría de controladores!
La factoría de controladores es el componente de ASP.NET MVC encargado de localizar e instanciar el controlador apropiado para procesar cada petición entrante. Por defecto, este trabajo lo realiza la claseDefaultControllerFactory
, pero como en otras ocasiones, la flexibilidad del framework MVC permite sustituir muy fácilmente este componente por otro que realice la tarea que nos interesa.Dentro de la factoría de controladores, el método GetControllerType() es utilizado por el framework para localizar el tipo (la clase) de controlador en función del nombre obtenido desde los parámetros de ruta. De hecho, este mismo método es el que utilizamos hace más de un año para saltarnos a la torera la convención de nombrado de controladores del framework.
De hecho, si heredamos de la factoría de controladores por defecto, basta con sobrescribir este método
GetControllerType()
para conseguir el comportamiento que pretendemos. En primer lugar, ejecutamos la lógica por defecto; sólo en el caso de no encontrar un controlador utilizaremos por defecto el controlador AutoController
que creamos en el post anterior, de forma que sea él el que se encargue de proporcionar la implementación automática de sus acciones:public class AutoControladoresControllerFactory: DefaultControllerFactory
{
protected override Type GetControllerType(RequestContext requestContext,
string controllerName)
{
return base.GetControllerType(requestContext, controllerName)
?? typeof (AutoController);
}
}
Ya lo último que necesitamos es indicar al framework la factoría de controladores que debe utilizar, la clase
AutoControladoresControllerFactory
, introduciendo el siguiente código en el archivo global.asax.cs:protected void Application_Start()
{
// Establecemos la nueva factoría de controladores...
ControllerBuilder.Current.SetControllerFactory(
typeof(AutoControladoresControllerFactory)
);
// Y el código habitual en el Application_Start()
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
Y con eso, hemos terminado. A partir de ese momento, todas las peticiones cuyo controlador sea imposible localizar según el procedimiento estándar, serán procesadas por el controlador automático AutoController, que buscará para cada acción una vista y la retornará mágicamente al usuario.
Así, una petición de tipo
GET /Home/Services
, que requeriría normalmente la existencia de una clase controlador HomeController
y un método de acción Services()
, podrá ser resuelta sin implementar ninguno de estos dos elementos, siempre que exista una vista definida en ~/Views/Home/Products.aspx
. Ya en el post anterior comenté algunas contraindicaciones que podía tener la utilización de esta técnica. ¡No dejes de revisarlo si piensas emplearla en producción!A modo de demo, he colgado en Skydrive un ejemplo (para Visual Studio 2010) en el que se ha eliminado directamente el controlador Home, y han sido añadidas diversas vistas a las que se puede acceder utilizando estos automatismos.
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 11:45 p. m.
Nadie ha comentado la entrada, ¿quieres ser el primero?
Etiquetas: asp.net, aspnetmvc, desarrollo
domingo, 20 de junio de 2010
Estos son los enlaces publicados en Variable not found en Facebook desde el viernes, 09 de abril de 2010 hasta el domingo, 20 de junio de 2010. Espero que te resulten interesantes. :-)
Publicado en: Variable not found
- Gestión de errores en ASP.NET MVC con Elmah.
Fecha: 17/06/2010 - Cadenas de texto seguras usando System.SecureString... ¿desde cuándo está eso ahí? :-D
Fecha: 17/06/2010 - Un vistazo rápido a jQuery. Muy bueno.
Fecha: 17/06/2010 - Maarten Balliauw ha publicado la versión 2.0 de su SiteMap Provider para ASP.NET MVC. Fecha: 16/06/2010
- Eduard Tomàs muestra detalladamente cómo crear validaciones personalizadas en ASP.NET MVC
Fecha: 16/06/2010 - Creación de un proveedor de caché personalizado para ASP.NET.
Fecha: 16/06/2010 - Jose Miguel Torres continúa recorriendo las colecciones de .NET. Segunda genial entrega de la serie.
Fecha: 16/06/2010 - Alfredo Fernández: JQuery 1.4.2 Cheat Sheet (.pdf)
Fecha: 15/06/2010 - Un vistazo de cerca al atributo [HiddenInput] en ASP.NET MVC.
Fecha: 15/06/2010 - Uso de LINQPad para realizar consultas a fuentes OData (con ejemplo práctico sobre StackOverflow).
Fecha: 14/06/2010 - Textbox con autocompletado usando anotaciones y plantillas de edición para MVC 2.
Fecha: 14/06/2010 - Eduard Tomàs "Sobre ir recorriendo enumerables" o también IEnumerable vs IEnumerator
Fecha: 11/06/2010 - Prevenir (al menos un poco) el copiado/pegado de texto en campos de un formulario web. Válido en Webforms, MVC o HTML.
Fecha: 11/06/2010 - Otra aportación de Microsoft a jQuery: Globalization Plugin.
Fecha: 11/06/2010 - Cómo detectar procesos que no responden.
Fecha: 11/06/2010
Publicado en: Variable not found
martes, 15 de junio de 2010
Aunque las convenciones propuestas por el framework ASP.NET MVC nos ayudan a estructurar nuestras aplicaciones y, la mayoría de veces, a ser más productivos, de vez en cuando también nos obligan a introducir código repetitivo para respetar el patrón propuesto.
Por ejemplo, en el caso de controladores con acciones que retornan la vista por defecto, solemos utilizar un código como el siguiente:
No es que sea algo terrible, pero en controladores con muchas acciones de este tipo puede resultar un poco pesado… ¿no podríamos hacer algo para mejorar esto?
Una vía muy rápida para hacerlo es sobrescribir el método
Recordemos que cuando una petición llega a un controlador, se ejecuta el método cuyo nombre coincide con el de la acción invocada; en caso de no existir, el framework llamada a
Para ello, basta con crear una clase base llamada
¿Sencillo, no? Lo único que hacemos en el código es utilizar la colección de
Si no es posible localizar una vista para la acción invocada, se ejecutará el tratamiento por defecto para esta situación, que no es más que el lanzamiento de una excepción de tipo
¡Y eso es todo! A partir de este momento, todas las clases controlador que hereden de
Por ejemplo, el controlador que escribíamos al comienzo de este post podría quedar de la siguiente forma, bastante más compacta:
Cada petición recibida por el controlador que no se encuentre implementada de forma explícita será procesada con el automatismo introducido en
Por ejemplo, sería posible acceder a vistas directamente, sólo con saber su nombre, lo que en algunos escenarios puede resultar peligroso desde el punto de vista de la seguridad del sistema.
Obviamente, la técnica tampoco será válida en aquellas ocasiones en que la vista espere recibir algún tipo de información del controlador (como datos de vista, o la indicación de utilización de una página maestra concreta), o cuando la acción deba estar decorada con un filtro.
En estos casos, estas acciones concretas deberán seguir siendo implementadas explícitamente en el controlador, aunque el resto puedan seguir siendo procesadas de forma automática:
En resumen, en este post hemos estudiado una técnica que nos permite crear controladores capaces de aportar un comportamiento por defecto para todas las peticiones realizadas hacia el mismo, ahorrándonos la escritura de acciones que simplemente retornan la vista por defecto.
Y aunque, como todo, en la práctica presenta limitaciones y peligros, su uso puede ser interesante en sitios web sin grandes requisitos de seguridad, como webs de información pública, cuyos controladores sean principalmente del tipo descrito.
Publicado en: Variable not found.
Por ejemplo, en el caso de controladores con acciones que retornan la vista por defecto, solemos utilizar un código como el siguiente:
public class HomeController: Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Company()
{
return View();
}
public ActionResult Services()
{
return View();
}
public ActionResult Contact()
{
return View();
}
}
No es que sea algo terrible, pero en controladores con muchas acciones de este tipo puede resultar un poco pesado… ¿no podríamos hacer algo para mejorar esto?
Controladores automáticos
Si observamos el código del controlador anterior, vemos que la lógica de ejecución es muy simple: cada acción implementada retorna al usuario la vista que le corresponde según convención. Obviamente se trata de un comportamiento que puede ser generalizado jugando con los mecanismos de extensión del framework.Una vía muy rápida para hacerlo es sobrescribir el método
HandleUnknownAction()
de la clase Controller
, descrito por aquí hace tiempo, que nos permite procesar las peticiones realizadas a acciones no existentes en el controlador.Recordemos que cuando una petición llega a un controlador, se ejecuta el método cuyo nombre coincide con el de la acción invocada; en caso de no existir, el framework llamada a
HandleUnknownAction()
, permitiéndonos tomar el control de la situación. En nuestro caso, podríamos introducir en este método la lógica para retornar al usuario, de forma automática, una vista cuyo nombre coincide con el de la acción, siguiendo la convención de nombrado estándar.Para ello, basta con crear una clase base llamada
AutoController
, e introducir el siguiente código para tener el problema resuelto:public class AutoController : Controller
{
protected override void HandleUnknownAction(string actionName)
{
// Intentamos localizar una vista con el nombre de la acción...
ViewEngineResult viewResult = ViewEngines.Engines.FindView
(this.ControllerContext, actionName, null) ;
if (viewResult.View != null)
{
View(actionName).ExecuteResult(ControllerContext);
return;
}
// Si no hemos encontrado nada, seguimos el
// comportamiento por defecto…
base.HandleUnknownAction(actionName);
}
¿Sencillo, no? Lo único que hacemos en el código es utilizar la colección de
ViewEngines
para buscar una vista cuyo nombre coincida con el de la acción que se está intentando ejecutar, retornándola al usuario cuando sea posible localizarla.Si no es posible localizar una vista para la acción invocada, se ejecutará el tratamiento por defecto para esta situación, que no es más que el lanzamiento de una excepción de tipo
HttpException
con el error 404 (not found).¡Y eso es todo! A partir de este momento, todas las clases controlador que hereden de
AutoController
incluirán este comportamiento, por lo que será posible obviar la implementación de métodos cuya única misión sea retornar la vista por defecto según convención.Por ejemplo, el controlador que escribíamos al comienzo de este post podría quedar de la siguiente forma, bastante más compacta:
public class HomeController: AutoController
{
}
Pero ojito, que no es oro todo lo que reluce…
Eso sí, antes de usar esta técnica tenemos que tener claro lo que significa realmente para no toparnos con sorpresas desagradables.Cada petición recibida por el controlador que no se encuentre implementada de forma explícita será procesada con el automatismo introducido en
HandleUnknowAction()
sin pasar por ningún tipo de filtro, ni enviar información alguna en el ViewData
.Por ejemplo, sería posible acceder a vistas directamente, sólo con saber su nombre, lo que en algunos escenarios puede resultar peligroso desde el punto de vista de la seguridad del sistema.
Obviamente, la técnica tampoco será válida en aquellas ocasiones en que la vista espere recibir algún tipo de información del controlador (como datos de vista, o la indicación de utilización de una página maestra concreta), o cuando la acción deba estar decorada con un filtro.
En estos casos, estas acciones concretas deberán seguir siendo implementadas explícitamente en el controlador, aunque el resto puedan seguir siendo procesadas de forma automática:
public class HomeController: AutoController
{
// GET /Home/Customers
// Sólo para usuarios registrados
[Authorize]
public ActionResult Customers()
{
return View();
}
// GET /Home/References
public ActionResult References()
{
var services = new AppServices();
return View(services.GetReferences());
}
// GET /Home/{CualquierOtraCosa}
// Procesado por defecto, retorna la vista {CualquierOtraCosa}
}
En resumen, en este post hemos estudiado una técnica que nos permite crear controladores capaces de aportar un comportamiento por defecto para todas las peticiones realizadas hacia el mismo, ahorrándonos la escritura de acciones que simplemente retornan la vista por defecto.
Y aunque, como todo, en la práctica presenta limitaciones y peligros, su uso puede ser interesante en sitios web sin grandes requisitos de seguridad, como webs de información pública, cuyos controladores sean principalmente del tipo descrito.
Publicado en: Variable not found.
domingo, 13 de junio de 2010
Estos son los enlaces publicados en Twitter y Variable not found en Facebook desde el lunes, 07 de junio de 2010 hasta el domingo, 13 de junio de 2010. Espero que os resulten interesantes :-)
Publicado en: Variable not found
- Eduard Tomàs "Sobre ir recorriendo enumerables" o también IEnumerable vs IEnumerator
Fecha: 11/06/2010 - Prevenir (al menos un poco) el copiado/pegado de texto en campos de un formulario web. Válido en Webforms, MVC o HTML.
Fecha: 11/06/2010 - Otra aportación de Microsoft a jQuery: Globalization Plugin.
Fecha: 11/06/2010 - Cómo detectar procesos que no responden.
Fecha: 11/06/2010 - Transactional File Manager: operaciones con archivos de forma transaccional.
Fecha: 10/06/2010 - Permitiendo caracteres raros en el path y el querystring. Poderse, se puede; otra cosa es que se deba...
Fecha: 10/06/2010 - Persistencia de sesiones ASP.NET entre distintas instancias del navegador.
Fecha: 10/06/2010 - Disponible Visual Studio Pro Power Tools. Por fin un filtro al añadir referencias y ¡copiar y pegar código en HTML! :-)
Fecha: 09/06/2010 - Gestión global de la validación de peticiones en ASP.NET MVC.
Fecha: 09/06/2010 - Colecciones en .NET, magnífico post de José Miguel Torres. Inicio de una serie que promete.
Fecha: 09/06/2010 - Helper para facilitar el uso de jqGrid en ASP.NET MVC.
Fecha: 08/06/2010 - HTML 5 en un vistazo.
Fecha: 08/06/2010 - Plantilla de edición para botones de tipo radio en MVC 2.
Fecha: 08/06/2010 - Mapeo, DTO's y ViewModels en ASP.NET MVC.
Fecha: 07/06/2010
Publicado en: Variable not found
lunes, 7 de junio de 2010
Las plantillas de edición, incorporadas con la versión 2 de ASP.NET MVC, permiten crear muy fácilmente interfaces de edición reutilizables, y asociarlas a tipos de datos concretos.
En el caso de las fechas se trata de una práctica muy habitual, puesto que la edición por defecto para este tipo de campos casi nunca es suficiente y siempre tendremos necesidad de modificar este comportamiento.
Es decir, pongamos una entidad del Modelo como la siguiente:
Si generamos desde Visual Studio la vista de creación o edición por defecto de esta entidad, obtendremos un código, más o menos como el siguiente:
(Por cierto, ya he hablado por aquí en otra ocasión sobre cómo generar el código correcto del andamiaje de edición para las entidades del Modelo con propiedades de tipo DateTime, decimal o double).
Ejecutando ahora la solución y accediendo a esta vista de edición podremos comprobar que el resultado está bastante lejos del que seguro desearíamos obtener. En particular, la fecha se introduce en un cuadro de texto bastante desarbolado y muy poco profesional:
Vamos a ver paso a paso cómo mejorar esto utilizando los templated helpers, una característica introducida en ASP.NET MVC 2 que nos brinda un mecanismo de creación de plantillas de visualización y edición de propiedades muy potente y reutilizable.
Concretamente utilizaremos el widget Datepicker, incluido en el framework jQuery UI, que además de permitir la introducción manual de fechas con el formato correcto, permite la selección visual a través de un bonito calendario.
El post es un poco largo, pues iremos muy despacio y comentando cada paso, pero una vez sepáis hacerlo no tardaréis más de cinco minutos en activar este editor para todos los controles de introducción de fechas de vuestro sitio web :-)
La página de downloads de jQuery UI permite personalizar el contenido del paquete a descargar. Por ejemplo, si únicamente vamos a utilizar el widget “DatePicker”, podríamos desmarcar el resto de componentes para aligerar el peso del paquete final.
Para pruebas, lo más sencillo es dejar marcados todos los elementos, así no nos dejamos por detrás nada; en producción sería mejor descargar una versión más ligera, sólo con los componentes que vayamos a utilizar.
También debemos elegir el tema visual a emplear. Esto es importante, pues determina la apariencia visual de los widgets empleados. En nuestro caso, seleccionaremos el tema “Start”, aunque hay una gran variedad de ellos a elegir, e incluso desde el mismo sitio web puedes personalizarlos y crear temas nuevos.
Una vez hecho esto, pulsamos el botón download y salvamos en nuestro equipo el archivo .zip generado. De él tendremos que extraer:
La captura de pantalla adjunta muestra cómo quedaría el proyecto MVC tras incluir estos elementos.
De esta forma estamos diciéndole al framework, poco más o menos: “eh, genera un cuadro de texto para editar la propiedad
Pero como en este caso lo que nos interesa no es utilizar un cuadro de texto sino un editor más potente, modificamos dicha línea, dejándola como sigue:
Y ahora la cosa ha cambiado; la sustitución de
Este editor específico se trata de una vista parcial, una plantilla que podemos implementar en un archivo .ascx a nuestro antojo, incluyendo todos aquellos elementos que consideremos interesantes a la hora de ayudar al usuario a editar dicha propiedad.
Existen diversas vías para indicar a ASP.NET MVC la plantilla de edición a utilizar en cada caso, aunque aquí utilizaremos la forma más potente: la selección basada en el tipo de datos, un mecanismo compartido por la tecnología de datos dinámicos (Dynamic Data), que simplifica enormemente la construcción de interfaces.
Su funcionamiento es muy simple:
Otra ventaja es que esta solución es aplicable incluso a toda clase de tipos de datos. Es decir, podemos crear plantillas como “Boolean.ascx” para crear editores para valores lógicos, o “Persona.ascx” si lo que queremos es definir la plantilla para la edición de la clase
Observad que dado que vamos a implementar un editor para la clase
Comentamos rápidamente lo que podemos ver ahí:
Como podéis observar, estamos utilizando el helper
Y lo mejor es que a partir de este momento todas las fechas que vayamos a editar en nuestra aplicación podrán beneficiarse de este editor simplemente introduciendo en las vistas la llamada al helper
Como se puede comprobar, se trata de una solución muy elegante, productiva, fácil de mantener y respetuosa con el patrón MVC, de la que seguro no podréis prescindir en cuanto la utilicéis y veáis lo sencillo que resulta crearos vuestra propia biblioteca de editores personalizados.
Ah, dejo el proyecto de demostración, para Visual Studio 2008, en mi Skydrive, por si queréis comprobar "en directo" lo bien que queda ;-)
Publicado en: Variable not found.
En el caso de las fechas se trata de una práctica muy habitual, puesto que la edición por defecto para este tipo de campos casi nunca es suficiente y siempre tendremos necesidad de modificar este comportamiento.
Es decir, pongamos una entidad del Modelo como la siguiente:
public class Persona
{
[Required(ErrorMessage="Dime el nombre, anda")]
public string Nombre { get; set; }
[Required(ErrorMessage="Hey, este dato es fundamental")]
[DisplayName("Fecha de nacimiento")]
public DateTime FechaNacimiento { get; set; }
}
Si generamos desde Visual Studio la vista de creación o edición por defecto de esta entidad, obtendremos un código, más o menos como el siguiente:
Ejecutando ahora la solución y accediendo a esta vista de edición podremos comprobar que el resultado está bastante lejos del que seguro desearíamos obtener. En particular, la fecha se introduce en un cuadro de texto bastante desarbolado y muy poco profesional:
Concretamente utilizaremos el widget Datepicker, incluido en el framework jQuery UI, que además de permitir la introducción manual de fechas con el formato correcto, permite la selección visual a través de un bonito calendario.
El post es un poco largo, pues iremos muy despacio y comentando cada paso, pero una vez sepáis hacerlo no tardaréis más de cinco minutos en activar este editor para todos los controles de introducción de fechas de vuestro sitio web :-)
1. Descargamos jQuery UI
El primer paso es hacernos con la infraestructura necesaria para implementar la solución, por lo que debemos descargar la librería jQuery UI. Aunque es un procedimiento sencillo, hay que tener cuidado con algunos detalles.Para pruebas, lo más sencillo es dejar marcados todos los elementos, así no nos dejamos por detrás nada; en producción sería mejor descargar una versión más ligera, sólo con los componentes que vayamos a utilizar.
También debemos elegir el tema visual a emplear. Esto es importante, pues determina la apariencia visual de los widgets empleados. En nuestro caso, seleccionaremos el tema “Start”, aunque hay una gran variedad de ellos a elegir, e incluso desde el mismo sitio web puedes personalizarlos y crear temas nuevos.
Una vez hecho esto, pulsamos el botón download y salvamos en nuestro equipo el archivo .zip generado. De él tendremos que extraer:
- por un lado, la hoja de estilos (.css) e imágenes utilizadas por el tema elegido, disponibles dentro de la carpeta
/css/start
del archivo .zip que hemos descargado. Descomprimimos esta carpeta sobre el directorio/Content
de nuestro proyecto MVC. - el archivo de scripts, jquery-ui-1.8.1.custom.min.js, disponible en la carpeta
/js
del fichero .zip, que descomprimimos sobre la el directorio /Scripts de nuestro proyecto.
La captura de pantalla adjunta muestra cómo quedaría el proyecto MVC tras incluir estos elementos.
2. Modificamos la vista
Si acudimos a la vista de edición de la entidad, observamos que la propiedad de tipo fecha se edita a través del control generado por el siguiente código:<%= Html.TextBoxFor(model => model.FechaNacimiento) %>
De esta forma estamos diciéndole al framework, poco más o menos: “eh, genera un cuadro de texto para editar la propiedad
FechaNacimiento
del modelo”, es decir, explícitamente le indicamos que la fecha de nacimiento sea editada con un text box.Pero como en este caso lo que nos interesa no es utilizar un cuadro de texto sino un editor más potente, modificamos dicha línea, dejándola como sigue:
<%= Html.EditorFor(model => model.FechaNacimiento) %>
Y ahora la cosa ha cambiado; la sustitución de
TextBoxFor
por EditorFor
viene a ser como hubiéramos cambiado la frase anterior por “eh, genera un editor específico para la propiedad FechaNacimiento
del Modelo”.Este editor específico se trata de una vista parcial, una plantilla que podemos implementar en un archivo .ascx a nuestro antojo, incluyendo todos aquellos elementos que consideremos interesantes a la hora de ayudar al usuario a editar dicha propiedad.
Existen diversas vías para indicar a ASP.NET MVC la plantilla de edición a utilizar en cada caso, aunque aquí utilizaremos la forma más potente: la selección basada en el tipo de datos, un mecanismo compartido por la tecnología de datos dinámicos (Dynamic Data), que simplifica enormemente la construcción de interfaces.
Su funcionamiento es muy simple:
- Durante la ejecución de la llamada al helper
Html.EditorFor()
, el framework examinará la propiedad que deseamos editar, determinando que se trata, en este caso, de un tipoDateTime
. - Si existe una plantilla llamada “DateTime.ascx” en un directorio definido por convención, renderizará su contenido como editor para la propiedad.
- En caso contrario, intentará generar un editor por defecto.
EditorFor()
, se utilizará la plantilla que hayamos creado para ello. De lo más DRY, vaya :-)Otra ventaja es que esta solución es aplicable incluso a toda clase de tipos de datos. Es decir, podemos crear plantillas como “Boolean.ascx” para crear editores para valores lógicos, o “Persona.ascx” si lo que queremos es definir la plantilla para la edición de la clase
Persona
del Modelo.3. Creamos la plantilla de edición
Al tratarse de componentes de la Vista, las plantillas de edición de un tipo concreto las crearemos dentro de la carpeta /Views del proyecto, y más concretamente en:/Views/{ControladorActual}/EditorTemplates
, si lo que queremos es que la plantilla sea utilizada exclusivamente dentro del contexto de un controlador./Views/Shared/EditorTemplates
, lo más frecuente, si queremos que la plantilla de edición sea utilizada desde cualquier punto del sistema.
Observad que dado que vamos a implementar un editor para la clase
DateTime
, estamos creando una vista parcial fuertemente tipada hacia dicho tipo. El código para la plantilla DateTime.ascx
es el siguiente:- La vista parcial hereda de
ViewUserControl<DateTime>
, pues es el tipo de datos sobre el que va a operar. La propiedadModel
a nivel de vista será por tanto una fecha. - Lo primero que hacemos es generar, ahora sí, un cuadro de edición para editar el valor suministrado. Aquí destacan varios detalles:
- en primer lugar, el nombre o identificador de la propiedad está como cadena vacía. Esto es así porque es la vista que utiliza esta plantilla la que le suministrará el nombre; tened en cuenta que el mismo editor podría ser utilizado para varias propiedades, por lo que no tendría sentido introducir aquí el nombre de ninguna de ellas.
- A continuación asignamos un valor inicial al control, que obtenemos formateando la fecha.
- Por último, añadimos varios atributos HTML al tag <input>, como el tamaño máximo del texto o la clase CSS que queremos utilizar.
- Incluimos también en la vista un texto fijo indicando el formato de la fecha (dd/mm/aaaa).
- Finalmente, creamos el script que hace la magia. Detectamos si están presentes tanto jQuery como Datepicker y, en caso afirmativo, inicializamos el plugin para que tome el control del cuadro de edición que acabamos de generar.
4. Incluimos las referencias a las librerías de scripts y estilos
Por último, sólo nos falta añadir las referencias a las librerías y estilos en el punto donde nos interese:- si vamos a utilizar el editor u otras características de jQuery, o UI por toda la aplicación, lo más razonable es incluirlas en la página maestra del sitio,
- en caso contrario, si se trata de un uso puntual, podemos añadirlas exclusivamente a la vista donde se necesite.
<script src="<%= Url.Content("~/Scripts/jquery-1.4.1.min.js")%>"
type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/jquery-ui-1.8.1.custom.min.js")%>"
type="text/javascript"></script>
<script src="<%= Url.Content("~/Scripts/jquery.ui.datepicker-es.js")%>"
type="text/javascript"></script>
<link href="<%= Url.Content("~/Content/start/jquery-ui-1.8.1.custom.css")%>"
rel="stylesheet" type="text/css" />
Como podéis observar, estamos utilizando el helper
Url.Content
para obtener la ruta absoluta de los recursos.5. Y… ¡voilà!
¡Hemos terminado! Si ejecutamos ahora nuestra aplicación, podremos comprobar que tanto el aspecto como la usabilidad del resultado han mejorado notablemente:Html.EditorFor()
:-). Como se puede comprobar, se trata de una solución muy elegante, productiva, fácil de mantener y respetuosa con el patrón MVC, de la que seguro no podréis prescindir en cuanto la utilicéis y veáis lo sencillo que resulta crearos vuestra propia biblioteca de editores personalizados.
Ah, dejo el proyecto de demostración, para Visual Studio 2008, en mi Skydrive, por si queréis comprobar "en directo" lo bien que queda ;-)
Publicado en: Variable not found.
domingo, 6 de junio de 2010
Estos son los enlaces publicados en Variable not found en Facebook desde el lunes, 24 de mayo de 2010 hasta el domingo, 06 de junio de 2010. Espero que os resulten interesantes :-)
Publicado en: Variable not found
- Validación condicional en ASP.NET MVC.
Fecha: 04/06/2010 - RT Bruno Capuano: New blog post: [EVENTO] Java vs Net vs Java vs Net vs Java vs Net …
Fecha: 03/06/2010 - Uso de diccionarios para sustituir bloques switch o múltiples sentencias if.
Fecha: 02/06/2010 - Smacchia comenta la orientación de C# 5 hacia la metaprogramación.
Fecha: 02/06/2010 - Interesante howto sobre validación en ASP.NET MVC (en PDF descargable).
Fecha: 02/06/2010 - Creación de informes con el control Chart y ASP.NET MVC.
Fecha: 02/06/2010 - RT Eduard Tomàs: ModelBinders vs Value Providers y un ejemplo de ello usando JSON...
Todo lo que los geeks de Windows y .Net tienen que contar en sus blogs y en nuestros foros
Fecha: 01/06/2010 - Uso de ViewModels dinámicos para eliminar lógica de presentación en las vistas. Fecha: 31/05/2010
- Evolución del sonido en nuestro PC, utilizando como muestra la BSO de Monkey Island. Fecha: 31/05/2010
- JM Alarcón Aguín: "Serializar objetos comprimiéndolos antes para ahorrar espacio y los problemas que podremos tener"
Fecha: 31/05/2010 - La conversión entre tipos no cumple la propiedad distributiva.
Fecha: 31/05/2010 - Magnífico post de Gisela Torres sobre OAuth.
Fecha: 31/05/2010 - Uso del plugin jQuery Autocomplete con ASP.NET MVC.
Fecha: 28/05/2010 - Código fuente de ejemplo de proveedor EF4 para SQL Server.
Fecha: 28/05/2010 - Creación de proyectos que contienen sólo archivos estáticos en Visual Studio.
Fecha: 28/05/2010 - Proyectos open source para facilitar la interoperabilidad con archivos .pst de Outlook.
Fecha: 26/05/2010 - Publicado Fluent NHibernate 1.1.
Fecha: 26/05/2010 - Second Nug: Tercer aniversario de SNUG
Fecha: 25/05/2010 - Retorno de información de contacto desde ASP.NET MVC: vCard ActionResult.
Fecha: 24/05/2010 - Abstracciones de clases intrínsecas de ASP.NET usadas por el framework MVC para facilitar el testeo.
Fecha: 24/05/2010
Publicado en: Variable not found