Modificar los mensajes de validación por defecto en ASP.NET MVC 2

ASP.NET MVC 2 El sistema de validaciones integrado en ASP.NET MVC 2, basado en la especificación de restricciones utilizando los atributos definidos en el espacio de nombres System.ComponentModel.DataAnnotations, permiten la introducción de mensajes de error personalizados, como en el siguiente ejemplo:

[Range(100, 230, ErrorMessage="La altura debe estar comprendida entre {1} y {2}")]
public double Height { get; set; }
Y otra posibilidad es externalizar estos mensajes a archivos de recursos, y crear versiones localizadas de los mismos:

[Required(
    ErrorMessageResourceName="CampoObligatorio",
    ErrorMessageResourceType = typeof(Resources.Mensajes))]

public string Name { get; set; }
De esta forma, todos los atributos mediante los cuales podemos indicar restricciones del modelo permiten la especificación de un mensaje de error descriptivo.

Sin embargo, hay dos tipos de errores de validación en los que no es tan obvia la forma de indicar el texto del mensaje, debido a que no se generan por restricciones especificadas en atributos, sino basados en el tipo de la propiedad.

Por ejemplo, supongamos el siguiente código, perteneciente a una entidad de datos:

public class Entidad
{
  public DateTime Fecha { get; set; }
  public int Numero { get; set; }
}
Aunque no hayamos indicado ninguna anotación que limite el contenido de sus dos propiedades, sí que existen de forma implícita dos condicionantes: el primero de ellos, que al tratarse de tipos valor no se admitirán valores nulos (o vacíos, a nivel de controles de formularios); y el segundo, que los valores introducidos deben ser convertibles a los tipos DateTime e int, respectivamente.

La siguiente captura de pantalla muestra un formulario de edición de la entidad en los que se han producido estos errores de validación:

Editando la entidad

Propiedades implícitamente obligatorias

El mensaje “The XX field es required” es el texto de error por defecto para las propiedades de tipo valor, implícitamente obligatorias, y es el mismo que aparece cuando utilizamos la anotación [Required] sin especificar ningún mensaje de validación.

Para modificarlo basta decorar la propiedad con dicho atributo y especificar en él el contenido del mensaje, o la forma de localizar el texto en los recursos de la aplicación, de la misma forma que haríamos con un tipo referencia, como un string.

public class Entidad
{
   [Required(ErrorMessage = "Campo obligatorio")]
   public DateTime Fecha { get; set; }
 
   [Required(ErrorMessage = "Campo obligatorio")]
   public int Numero { get; set; }
}
Dado que este código es algo anti-DRY, todavía podemos mejorarlo un poco creando nuestro propio atributo personalizado:

public class Entidad
{
   [Requerido]
   public DateTime Fecha { get; set; }
 
   [Requerido]
   public int Numero { get; set; }
}
 
public class RequeridoAttribute : RequiredAttribute
{
   public RequeridoAttribute()
   {
      this.ErrorMessage = "Campo obligatorio";
   }
}

¿Problemas con el cambio de tipo?

El otro error, “The value XX is not valid for YY”, es algo más complicado  dado que no existe ningún atributo en el que podamos indicar de forma explícita el mensaje a utilizar, como hemos hecho en el caso anterior.

Para sustituir el mensaje por defecto es necesario utilizar un archivo de recursos en el que tendremos que introducir el texto que queramos utilizar en estos casos. Para ello, añadiremos en primer lugar una carpeta de recursos globales:

Añadir una carpeta de recursos globales

Y en su interior un archivo de recursos, llamado por ejemplo Mensajes.resx, en el que introducimos un string con el nombre PropertyValueInvalid, cuyo valor será el mensaje de error que queremos mostrar cuando se produzca un error de conversión:

PropertyValueInvalid

Observad que el interior del mensaje {0} será sustituido por el valor incorrecto, y {1} por la descripción de la propiedad que está generando el error.

El último paso para que ASP.NET MVC framework reconozca dónde debe buscar este recurso es indicar en la inicialización de la aplicación el nombre del archivo (o clase) que lo contiene:

 
protected void Application_Start()
{
   ... // Otras inicializaciones
 
   DefaultModelBinder.ResourceClassKey = "Mensajes";
}

Tras aplicar estos cambios, si ejecutamos la aplicación podremos comprobar que hemos conseguido nuestros objetivos:

Validaciones con mensajes personalizados

Publicado originalmente en: Modificar los mensajes de validación por defecto en ASP.NET MVC 2

Hey, ¡estoy en Twitter!

TempData en ASP.NET MVC 2

ASP.NET MVC 2TempData es un diccionario disponible a nivel de controladores y vistas del framework ASP.NET MVC que nos permite almacenar objetos de forma similar a la colección ViewData, pero, a diferencia de ésta, es capaz de mantener su contenido entre peticiones.

De hecho, es un recurso habitualmente utilizado cuando necesitamos enviar información desde una acción a otra tras realizar una redirección. Por ejemplo, ante una petición dirigida hacia la acción “Milestone” en un controlador como el siguiente:

public ActionResult Milestone() 
{
  TempData["Message"] = "He pasado por aquí";
  RedirectToAction("ShowMessage");
}
 
public ActionResult ShowMessage()
{
  return View();
} 

… podríamos tener en la plantilla de vista ShowMessage.aspx acceso directo a la entrada del TempData almacenada en la petición que inició la secuencia:

<p class="msg"><strong><%= TempData["Message"] %></strong></p>

Pues bien, la beta de ASP.NET MVC 2 introdujo en el comportamiento de este diccionario una serie de cambios que merecen ser comentados.

En primer lugar, ha sido modificado el ciclo de vida de las entradas existentes en el TempData. Ahora cada elemento del diccionario es analizado al finalizar la ejecución del controlador (concretamente su método ExecuteCore()); aquellos que estén “marcados” continuarán viviendo en el mecanismo de persistencia elegido (por defecto, en una variable de sesión del usuario) y el resto serán eliminados sin piedad.

Internamente se procede de la siguiente manera: al comenzar el proceso de la petición, se cargan en la propiedad TempData del controlador los valores almacenados en el proveedor de datos temporales,  un objeto que implementa el interfaz ITempDataProvider. La implementación por defecto utiliza la clase SessionStateTempDataProvider para almacenar la información en  la variable de sesión “__ControllerTempData”.

En este momento, todas las entradas presentes en el diccionario son marcadas como candidatas a ser conservadas.To be or not to be...

Si desde cualquier punto del código del controlador o la vista se obtiene el valor de una entrada del diccionario, como en el ejemplo de vista ShowMessage anteriormente mostrado, se eliminará la marca de supervivencia y pasarán a estar en la cuerda floja.

Al finalizar la ejecución del controlador, se recorren aquellas entradas del diccionario que no estén marcadas y se eliminan del diccionario. Finalmente, éste es salvado a través del proveedor de datos temporales actual.

Sólo hay una excepción para el caso anterior: las redirecciones. Éstas, en su método ExecuteResult(), incluyen una llamada al método Keep() del diccionario TempData actual, lo que provoca que todas las entradas del mismo sean marcadas para su conservación. Por tanto, una acción que retorne un tipo RedirectToRouteResult, siempre conservará el TempData intacto.

Como consecuencia, una forma de evitar la eliminación de una entrada y forzar su conservación al finalizar la petición actual es utilizando TempData.Keep(key), siendo key la clave de la misma,  o generalizando como en el caso anterior, TempData.Keep(), que salvará todas las entradas almacenadas.

Pero ojo, que esto puede provocar un efecto no deseado. Dado que por defecto las entradas al diccionario no van a eliminarse salvo que sean leídas, puede dar lugar a contenidos perennes en el estado de sesión del usuario. O en otras palabras, si introducimos en TempData una entrada con un objeto pesado y éste nunca es obtenido, permanecerá en la sesión del usuario hasta que ésta desaparezca… supongo que no es necesario comentar lo desastroso que puede ser esto, no? ;-D

Otro aspecto curioso es que cualquier consulta al TempData hará que la entrada sea marcada para su eliminación… incluso si estamos consultándola desde el depurador de Visual Studio. Por tanto, cuidado con esto, que puede provocar algún dolor de cabeza.

Aunque algo denostado, TempData sigue siendo una opción válida para el traspaso de información entre distintas peticiones, aunque siempre usado con moderación y sentido común. 

Publicado en: Variable not found.
Hey, ¡estoy en twitter!

Y después de ASP.NET MVC 2… ¿qué?

ASP.NET MVC Estando todavía calentito el horno del que acaba de salir ASP.NET MVC 2, es curioso conocer algo sobre el próximo plato que están preparando Haack y su equipo: ¡ASP.NET MVC 3!

Ya se han publicado algunas de las líneas y objetivos que guiarán los futuros desarrollos y determinados detalles que probablemente serán incluidos, aunque obviamente todavía pueden variar sustancialmente. Las principales áreas de atención son en estos momentos:

  • aumentar la productividad de los desarrolladores,
  • facilitar aún más el uso de Ajax,
  • incluir mejoras arquitecturales,
  • y aumentar el rendimiento.

El aumento de productividad irá ligado a la introducción de un nuevo conjunto de helpers destinados a realizar tareas muy comunes en el desarrollo de aplicaciones web, como la implementación de rejillas de datos (grids) paginados.

Asimismo, se dará soporte a nuevos atributos de validación además de los ya incluidos en las anotaciones de datos de ASP.NET 4.

Otra línea en estudio es la introducción de herramientas basadas en línea de comandos, alternativas a las incluidas en Visual Studio.

Para facilitar el uso de Ajax se introducirán nuevos helpers que simplifiquen la implementación de escenarios habituales, como los controles de selección de fecha o cuadros de edición con auto-completado.
También se considera interesante ampliar los helpers existentes para permitir la actualización parcial de varias zonas de la página, e incluir soporte para plantillas en cliente, que permitan añadir el marcado muy rápidamente a datos retornados en formato JSON desde el controlador.

Desde el punto de vista arquitectural, se planea seguir flexibilizando el framework, permitiendo nuevos puntos de inyección de dependencias, como la instanciación de clases del Modelo desde el binder, o en filtros de acción.Piezas de un sistema

Se prevé también la creación de una factoría de controladores para MEF (Managed Extensibility Framework) que permitan ampliar las funcionalidades de un sistema mediante sus sencillos mecanismos de extensibilidad, sin necesidad de recompilar.

Se incrementarán también las herramientas de generación de andamiaje de aplicaciones para acelerar la implementación de escenarios comunes, como los habituales CRUD.

Y respecto al rendimiento, el equipo está estudiando nuevas técnicas para mejorar el cacheo de respuestas, y soluciones como aumentar el control sobre el estado de sesión, permitiendo activarlo o desactivarlo para mejorar la eficiencia.

En cualquier caso, lo que sí ha dejado claro Phil es que ASP.NET MVC 2 será la última versión del framework con soporte para ASP.NET 3.5 SP1.

Fuente: Roadmap de ASP.NET MVC.
Publicado en: Variable not found.
Hey, ¡estoy en twitter!

ASP.NET MVC 2 final, ya disponible

¡ASP.NET MVC 2! Hace unos minutos en Twitter se propagaba la noticia de la disponibilidad de la versión final de ASP.NET MVC 2, que puedes descargar ya desde el sitio web de Microsoft.

Según se indica en el documento de notas de la revisión, y como era previsible, no se puede instalar en equipos con Visual Studio 2010 RC. Por lo demás, no se ha introducido ningún cambio destacable desde la anterior revisión, la segunda Release Candidate.

También se ha publicado el código fuente en CodePlex.

Publicado en: Variable not found.

30 Leyes epónimas relacionadas con el desarrollo de software (I)

Un epónimo es el nombre de una persona o lugar que cede su nombre a una época, pueblo, unidad, ley, etc. Son epónimos por ejemplo «Diesel», cedido por Rudolf Diesel, inventor de este tipo de motores, o «Hamburguesa», infame trozo de carne picada cuyo nombre procede de su lugar de origen.

Hace unos años, el gran Phil Haack posteó sobre leyes epónimas relacionadas con el desarrollo de software en «19 Eponymous Laws Of Software Development«, y seleccioné las que me resultaron más interesantes en un par de posts.

Ahora los he vuelto a maquetar y les he añadido un nuevo conjunto de leyes muy interesantes para todos los que nos dedicamos al mundo del desarrollo de software, y muchas de ellas incluso aplicables a otros ámbitos.

John Postel

1. Ley de Postel

Sé conservador en lo que hagas y liberal en lo que aceptes de los demás

Esta frase, de Jonathan Bruce Postel, también llamada Principio de Robustez, es la piedra filosofal del protocolo TCP, y está recogida en la RFC 793, sección 2.10, de septiembre de 1981.

 

C. Northcote Parkinson

2. Ley de Parkinson

El trabajo se extiende siempre hasta rellenar la totalidad del tiempo disponible para completarlo

Esta ley fue postulada inicialmente en 1955 por C. Northcote Parkinson en The Economist y más tarde entró a formar parte de su libro, basado principalmente en las experiencias de la administración británica.

 

 

Vilfredo Pareto

3. Principio de Pareto

Para muchos fenómenos, el 80% de las consecuencias derivan del 20% de las causas

Vilfredo Pareto fue un estudioso de la economía y sociología del siglo XIX, y se fijó que el 80% de las propiedades y riqueza estaban repartidas entre el 20% de la población, enunciando su famoso principio. A partir de ahí, se piensa que esta proporción es cierta en múltiples ocasiones, hasta en el número de bugs en el código fuente de un software, o el tiempo de desarrollo de funcionalidades.

 

 

 

Ted Sturgeon

4. Revelación de Sturgeon

El noventa por ciento de cualquier cosa es basura

Theodore Sturgeon era un autor de ciencia ficción americano que escribió esta frase defendiendo a este tipo de literatura de críticos que opinaban que el 90% era una porquería.

Hay un corolario que dice «La revelación de Sturgeon es cierta salvo para la basura, donde el 100% es basura«.

 

Lawrence J. Peter

5. El principio de Peter

En una jerarquía, todo individuo tiende a subir hasta alcanzar su nivel de incompetencia

Seguro que todos conocéis ejemplos de ello: un fabuloso desarrollador es ascendido a directivo en una empresa, la cual gana un gestor pésimo y pierde un programador excelente. Doble penalización. Lawrence J. Peter, pedagogo de profesión, ya lo enunció en 1968 en el libro El principio de Peter.

Douglas Hofstadter

6. Ley de Hofstadter

La realización de un trabajo siempre dura más de lo esperado, incluso habiéndose tenido en cuenta la Ley de Hofstadter

Esta genial y recursiva Ley creada por el científico, filósofo y académico estadounidense Douglas Hofstadter es absolutamente cierta. Y si no, pensad un poco, ¿cuántas veces habéis estimado plazos en un desarrollo, lo habéis incrementado de forma considerable por los imprevistos y aún así os habéis quedado cortos?

 

 

Edward A. Murphy

7. Ley de Murphy

Si algo puede ir mal, lo hará

La famosa ley, también enunciada en forma de tostada que recurrentemente cae con la mantequilla hacia abajo, fue dictada por Edward A. Murphy, Jr., mientras trabajaba para la fuerza aérea americana como ingeniero, diseñando un sistema de cohetes experimental. Sería lógico pensar que el experimento acabó en tragedia, pero parece ser que la creación y consideración de esta ley les ayudó a evitar graves desastres en sus pruebas.

 

Frederick Brooks

8. Ley de Brooks

Incluir trabajadores en un proyecto retrasado hará que éste avance aún más lentamente

Fred Brooks postuló esta ley en su famoso libro The Mythical Man-Month: Essays on Software Engineering como resultado de su experiencia en IBM. Existen variantes y corolarios como «Una señora es capaz de tener un hijo en nueve meses, pero este plazo no puede disminuir por muchas mujeres embarazadas que pongamos a ello». Simplemente genial.

 

 

No se dejó hacer la foto ;-) Este es uno de los diagramas usados en el paper 'How Do Committees Invent?' donde presentaba sus ideas

9. Ley de Conway

Cualquier software refleja la estructura organizacional de quien lo produjo

A pesar de que suena a guasa, la ley de Melvin Conway no puede ser más cierta. Una empresa con tres grupos de desarrollo tenderá a generar software distribuido en tres subsistemas, reflejo fiel de las relaciones entre los grupos participantes. Y por cierto, extrapolando un poco… ¿habéis pensado alguna vez que el software que se hace en vuestra empresa es un desastre? ¿creéis que con esta ley podríais obtener alguna conclusión? ;-D

 

 

Auguste Kerckhoffs

10. Principio de Kerckhoffs

En términos de criptografía, un sistema debería ser seguro incluso si todo sobre el mismo se conoce públicamente, salvo una pequeña porción de información

Es increíble que Auguste Kerckhoffs lingüista y criptógrafo alemán, enunciara en el siglo XIX este principio, base de todos los sistemas de criptografía de clave pública actuales.

 

 

 

 

Sigue leyendo en 30 Leyes epónimas relacionadas con el desarrollo de software (II)

Hey, ¡estoy en twitter!

Eliminar una entrada incorrecta del historial en IE8

Mi gran descubrimiento del día probablemente será una chorrada para la inmensa mayoría, pero también seguro que hay alguien que, como un servidor, no se había percatado hasta el momento de este detalle de IE8.

Como sabéis, la barra de direcciones de este navegador nos permite escribir la URL de la página que queremos visitar, pero podemos ahorrar mucho tiempo si tecleamos únicamente algunos caracteres contenidos en la misma: Internet Explorer buscará en el historial de sitios visitados y en los favoritos, mostrando aquellos sitios que contengan la cadena buscada.

Por ejemplo, escribiendo “vari”, mi Explorer 8 muestra las siguientes sugerencias:

IE8 sugiriendo sitios que contienen el texto "vari"
Sin embargo, si alguna vez introducís una dirección incorrecta, por ejemplo tecleando un carácter de más, u omitiendo alguno, esta URL será añadida al historial, y se mostrará como sugerencia también, efecto bastante incómodo.

En la captura anterior, se puede ver que Internet Explorer ofrece “varialablenotfound.com”, una dirección que tecleé de forma incorrecta tiempo atrás.

Pues mi gran descubrimiento es este: si paseamos el ratón sobre esta sugerencia, o la seleccionamos usando la tecla flecha abajo, aparece a la derecha un icono que nos permite eliminarla, para que no nos moleste más:

Icono para eliminar la entrada de las sugerencias
La explicación de que no lo haya visto hasta ahora es muy sencilla: al aparecer a la derecha del desplegable queda fuera del foco de atención en ese momento, que está justo en el lado contrario, y especialmente en pantallas con resolución muy ancha.

Por curiosidad he probado a ver si existía algo parecido en Chrome, Firefox y Opera, y ninguno incluye este detalle, que nos viene de perlas a los que somos algo muñones 😉

Crossposteado desde Eliminar una entrada incorrecta del historial en IE8.

Cambios en el retorno de datos JSON con MVC 2

aspnetmvc Con objeto de mejorar la seguridad de nuestras aplicaciones, la Release Candidate de ASP.NET MVC 2 introdujo un cambio importante en la forma de procesar peticiones que retornan información serializada como JSON: por defecto, ahora sólo se responde a peticiones de tipo POST.

Dado que en MVC 1.0 era justo al contrario, esta pequeña reorientación hace que aplicaciones que antes funcionaban correctamente dejen de hacerlo al migrarlas a la última versión del framework. Un ejemplo lo tenemos con las aplicaciones que aprovechan la potencia de jqGrid para mostrar y editar rejillas de datos. Recordemos que el intercambio de información entre cliente y servidor se realiza mediante llamadas Ajax que retornan siempre datos en notación JSON.

Los síntomas que notaremos en estos casos son muy simples: ¡las acciones que deberían devolvernos información dejan de hacerlo! En algunas ocasiones, dependiendo del uso que se dé en la vista a la la información retornada, es posible que aparezcan errores de script en el navegador, pero otras ni siquiera eso.

En cualquier caso, no es difícil dar con la solución. Con Firebug, Fiddler, o cualquier herramienta que nos permita monitorizar las peticiones, podremos observar que en la petición Ajax se está produciendo un error HTTP 500 (error interno de servidor):

image

Y si seguimos profundizando en dicha petición, podemos ahora conocer el mensaje descriptivo que envía el servidor, un auténtico detalle por parte del equipo de desarrollo de ASP.NET MVC 2, en el que incluso nos indican la solución al problema:

<html>
<head>
<title>This request has been blocked because sensitive 
information could be disclosed to third party web sites when 
this is used in a GET request. 
To allow GET requests, set JsonRequestBehavior to AllowGet.</title>
<style>

Ante esta situación, podemos optar por dos soluciones. La primera sería indicar explícitamente en la instancia del resultado, de tipo JsonResult, que queremos permitir el método GET, así:

return Json(data, JsonRequestBehavior.AllowGet);

Y otra posibilidad sería realizar las peticiones Ajax utilizando el método POST, algo que podemos conseguir muy fácilmente la mayoría de las veces. En el caso de los ejemplos con jqGrid, sería sustituyendo el ’GET’ por ‘POST’ en código:

[...]
jQuery("#list").jqGrid({
    url: '<%= Url.Action("ObtenerDatosGrid") %>',
    datatype: 'json',
    mtype: 'POST',    // <- Aquí
    colNames: ['Apellidos', 'Nombre', 'Fecha Nac.', 'Email'],
[...]

¡Gracias, Maxi, por los comentarios que inspiraron este post!

Crossposteado desde Cambios en el retorno de datos JSON con MVC 2 @ Variable not found