Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
domingo, 7 de marzo de 2010
ASP.NET MVC Esta es una respuesta rápida a una cuestión de Fred C., que me llega vía formulario de contacto en Variable not found, sobre un problemilla que también sufrí en algunas ocasiones, y he pensado que posiblemente pueda interesarle a alguien más, así que ahí va.

El escenario es el siguiente: tenemos en una vista un código para generar un enlace hacia una acción, como el mostrado a continuación:

<%= Html.ActionLink("Acceso externo",    // Texto del enlace
                    "Editar",            // Acción
                    "Productos",         // Controlador
                    new { id=Model.Id }) // Parámetros
%>

ActionLink() generanAl mostrarse la vista, ya en tiempo de ejecución, nos encontramos con que no se ha generado el enlace que pretendíamos, sino uno como el mostrado en la captura de pantalla adjunta, hacia la dirección/Home/Editar?Length=9.

En primer lugar, utilizando la ruta por defecto, vemos nos está llevando hacia el controlador “Home”, ¿pero no le habíamos dicho que era “Productos”?

Y en segundo lugar, ¿dónde está nuestro parámetro id? ¿De dónde sale ese parámetro Length con el valor 9?

La respuesta a este problema es bien sencilla aunque al principio puede provocarnos algún dolor de cabeza: estamos utilizando una sobrecarga incorrecta del método ActionLink().

Si observamos las distintas sobrecargas de este método, podremos comprobar que sólo una de ellas tiene una signatura compatible con la llamada que estamos utilizando:

public static string ActionLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string actionName,
    object routeValues,
    object htmlAttributes
)
Así, cuando en el código anterior estábamos pasando al método el nombre del controlador, en realidad lo que hacíamos era indicarle los parámetros de la llamada. Eso explica el parámetro Length=9 en la URL: dado que le enviamos un string de 9 caracteres, simplemente se trata de una serialización de sus propiedades.

Y, por tanto, los parámetros de la llamada que estábamos especificando, lo hacíamos como parte de los atributos HTML. De hecho, si analizamos el código fuente de la página generada, encontramos que el parámetro “id” ha sido introducido como un atributo HTML del enlace:

<a href="/Home/Editar?Length=9" id="8">Editar este producto</a>

La forma de solucionarlo es bien fácil, sólo hay que utilizar la sobrecarga apropiada, como:

<%= Html.ActionLink("Editar este producto", 
            "Editar",                     // Acción
            new {                         // Parámetros
            controller="Productos", 
            id=Model.Id 
}
) %> 
 
// O Bien:
 
<%= Html.ActionLink(
             "Editar este producto", 
             "Editar",               // Acción  
             "Productos",            // Controlador
             new { id=Model.Id },    // Parámetros
             null                    // Atributos HTML
) %> 

En fin, que se trata de un pequeño despiste a la hora de codificar, propiciado a veces por la gran cantidad de sobrecargas y la información, algo confusa, ofrecida por Intellisense que nos puede hacer perder unos minutos muy valiosos.

¡Gracias, Fred, por participar en Variable not found!
Por cierto, ¡estoy en Twitter!
lunes, 1 de marzo de 2010
BaseKit Los chicos de BaseKit me han invitado, bueno, y a 20 de vosotros también ;-), a probar su nueva herramienta, actualmente en fase de beta privada (si quieres conseguir un pase, lee el final del post).

BaseKit es una aplicación totalmente on-line que permite a diseñadores crear sitios web completos sin necesidad de tener conocimientos de HTML, javascript y, si apuramos, incluso ni de CSS, rompiendo así la brecha que tradicionalmente divide el mundo del diseño y del desarrollo web.

Otra ventaja para los que no se sienten cómodos lidiando con compañías de hosting es que el servicio cuenta con su propio alojamiento; en un par de clicks, el sitio web que estemos editando pasará a estar disponible en internet. De hecho, el alojamiento será el único concepto por el que BaseKit cobrará a los usuarios en el futuro.

Crear nuevo sitio web en basekitLa primera prueba de la facilidad con la que se pueden crear sitios web la encontramos al comenzar a trabajar con BaseKit, cuando tendremos que decidir cómo queremos crear el sitio web: importando un archivo Photoshop, seleccionando una plantilla base predefinida, o basándonos en un sitio disponible en la galería.

La primera opción permite subir directamente archivos en formato PSD cuyos contenidos y estructura serán utilizados para generar automáticamente la plantilla de la página.

Las siguientes opciones permiten tirar de elementos prediseñados, como plantillas o incluso sitios web completos, disponibles en la galería de BaseKit. Estas galerías todavía no ofrecen gran cantidad de elementos prediseñados, pero se entiende que es debido a que el producto está aún en fase de pruebas.

En cualquier caso, independientemente del modo de inicio lo que tendremos a continuación es un completo editor en el que podremos editar la página de forma visual, en plan drag&drop, de forma realmente sencilla.

De momento hay un buen número de widgets con los que crear los contenidos de la página, y obviamente tienen planes de seguir añadiendo nuevas posibilidades.

Editor de BaseKit

La siguiente captura muestra la página “Variable not found en BaseKit”, creada en sólo unos minutos, donde se integra información procedente de feeds RSS, Twitter, imágenes de Flickr, Google Maps, e incluso vídeos embebidos:
Variable not found en Basekit
Bueno, pues como ya hice en otras ocasiones, los 20 primeros usuarios que me hagan llegar su dirección de correo electrónico vía comentario a este post, formulario de contacto, Twitter, Facebook, o en persona ;-), tendrán acceso durante 30 días para publicar todas las páginas que deseen, con hosting gratuito durante todo el 2010.

Para las pruebas debes utilizar Firefox 3.5.5 o superior; de momento BaseKit no soporta IE, aunque están trabajando en ello.

¡Venga, os espero!

Publicado en: Variable not found.
lunes, 22 de febrero de 2010
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, permite 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 en: Variable not found
Hey, ¡estoy en Twitter!
miércoles, 17 de febrero de 2010
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!
domingo, 7 de febrero de 2010
Este post es la tercera y última entrega de la serie 30 Leyes epónimas relacionadas con el desarrollo de software. Puedes encontrar la segunda parte aquí.

Tim Bryce

21. Las leyes de Bryce

Así las llama él, aunque algunas encajarían mejor en una recopilación de frases célebres. Ahí van algunas, aunque pueden encontrarse más de 150 aquí.


Tal y como el uso de la tecnología va aumentando, disminuyen las habilidades sociales

El 85% del trabajo de desarrollo de todos los sistemas consiste en introducir modificaciones y mejoras

A la vez que la capacidad del hardware incrementa, el software se vuelve más pesado

Olvidar al ser humano durante el diseño del sistema provocará que el ser humano se olvide del sistema en el momento de echarlo a andar

[...]

Tim Bryce es un controvertido escritor y consultor de gestión de recursos de información (IRM), famoso entre otras cosas por sus aseveraciones sobre el ego, las manías y extrañezas de los desarrolladores, y sus consejos para manejarlos apropiadamente. Aparte de su habilidad para hacer amigos entre los programadores, es sin duda un gran experto en el mundo de las compañías de desarrollo de software, con más de 30 años a sus espaldas en este campo.

Eugene Spafford

22. Primer principio de Spaf

Si eres responsable de seguridad pero no tienes autoridad para establecer reglas y castigar sus incumplimientos, tu cargo real en la organización es asumir la culpa cuando ocurra algo grave

Eugene Spafford, más conocido como "Spaff", es un reputado experto en seguridad informática y profesor de la Purdue Univertity. Según parece, fue uno de los primeros en escribir un libro sobre virus informáticos en 1989, utilizar el término autopsia software para referirse al análisis de aplicaciones para intentar localizar a sus autores, y un sinfín de aportaciones al mundo de la seguridad en sistemas informáticos.

Además, es tan prolífico creando frases y analogías a la hora de explicar conceptos de informáticos que Mahesh V. Tripunitara, uno de sus estudiantes, mantiene una página donde las recoge: "The Page of Spaf's Analogies".

Aloysius Alzheimer

23. Ley de Alzheimer de la programación

Si lees un código que escribiste hace más de dos semanas es como si lo vieras por primera vez
Efectivamente, el psiquiatra y neurólogo alemán Aloysius Alzheimer no enunció esta ley a primeros del siglo pasado, pues estaba muy ocupado estudiando las enfermedades mentales de sus pacientes. Sin embargo, el síntoma de pérdida de memoria tan habitual en ellos propició la utilización de su nombre en esta Ley tan ligada a la escritura de código limpio, documentado y sencillo.

Roy Amara

24. Ley de Amara

Tendemos a sobreestimar el efecto de la tecnología en el corto plazo y a subestimarla a largo plazo
Esta ley, causa de la existencia de problemas debidos a excesos de optimismo o de la formulación de predicciones disparatadas, fue enunciada por Roy Amara, que fue presidente del Instituto para el Futuro, un grupo de investigación sin ánimo de lucro dedicado al análisis de tendencias que ayuden a la toma de decisiones basándose en predicciones sobre el futuro.

Barbara Liskov

26. Principio de Liskov

Los subtipos deben ser sustituibles por sus clases bases
O en otras palabras, que un subtipo no debe modificar el comportamiento esperado de la clase de la que hereda; de esta forma, si el subtipo puede sustituir a su clase base sin causar daños, la herencia será correcta. Citando a Enrique Place en PHPSenior, "No basta con ser hay que comportarse como tal".

Barbara Liskov es profesora del Massachusetts Institute of Technology (MIT) y fue la primera mujer en conseguir el doctorado en informática de Estados Unidos.

Hick no se dejó hacer la foto ;-)

25. Ley de Hick

El tiempo que se tarda en tomar una decisión aumenta a medida que se incrementa el número de alternativas
Puede sonar a obvio, pero la cuestión es que William Edmund Hick, pionero en psicología experimental y ergonomía, fue capaz de idear, a mediados del siglo pasado, la fórmula que explica por qué tardamos tanto tiempo en responder a un cuadro de diálogo con botones para Aceptar, Cancelar, Reintentar, Ignorar y Omitir:
T = blog2(n + 1)
Cosas de las matemáticas, seguro. :-D

Robert A. Heinlein, uno de los posibles padres del principio de Hanlon

27. Principio de Hanlon

Nunca le atribuya a la maldad lo que puede ser explicado por la estupidez
A pesar de su nombre, no está claro quién definió con tanta claridad su confianza en la capacidad del ser humano. Bill Clarke, Goethe, William James, Napoleón Bonaparte, Richard Feynmann, Einstein, Robert A. Heinlein (cuyo apellido podría haber degenerado en "Hanlon"), o un desconocido Robert J. Hanlon del que no existen demasiadas referencias podrían ser los padres de esta Ley tan utilizada por los hackers para definir situaciones creadas como consecuencia del trabajo de incompetentes sin mala intención.

Bill Joy

28. Ley de Joy

El número de empleados inteligentes en una empresa es una función logarítmica del número de empleados totales
También formulada como "no importa quien seas, la mayoría de la gente inteligente trabaja para otro", la Ley dictada por Bill Joy ofrece una visión un tanto pesimista (¿realista?) de nosotros mismos y nuestro entorno de trabajo. Pero ojo, que no lo decía cualquiera, que este señor es co-fundador de Sun y, probablemente, estuviera describiendo lo que veía.

Tim Lister

29. Ley de Lister

La gente bajo presión no piensa más rápido
Bonita frase para escribir en un post-it y pegárselo en la frente a alguien a ver si se da por aludido. Y es que efectivamente, la presión y la velocidad de pensamiento no son magnitudes proporcionales, pero es Tim Lister, un consultor, formador y escritor experto en gestión de riesgos en procesos de desarrollo de software, el que lo enunció de esta forma tan tajante y certera.



William of Ockham

30. La navaja de Occam

En igualdad de condiciones la solución más sencilla es probablemente la correcta
En el siglo XIV, Guillermo de Ockham, fraile franciscano y filósofo, postulaba de esta forma el principio de economía, utilizada en disciplinas tan dispares como la teología, informática o lingüística. De hecho, podríamos considerarlo la base de principios como KISS (Keep It Simple, Stupid), o YAGNI (You ain't gonna need it), asociados habitualmente a la programación extrema pero válidos en cualquier tipo de desarrollo.

Una curiosidad, el tercer episodio de la primera temporada de la serie House tenía este título, haciendo referencia a la solución del caso médico propuesto.




Fuentes:

Publicado en: Variable not found.