Enadan's Blog

lunes, febrero 6

Cambio de blog

Simplemente comunicar que he creado un nuevo blog, en ingles, y no creo que tenga tiempo de postear en ambos, asi que sintiendolo mucho de momento no volvere a escribir aqui.

Podeis seguir leyendo mis posts en http://blogs.clearscreen.com/enadan

Un saludo.

martes, enero 17

Lectura recomendada

Aqui dejo un link a un articulo sobre SOA que esta bastante bien.

Principios de diseño de servicios: patrones y antipatrones de servicios

martes, enero 10

Enhorabuena Miguel

Hace tiempo escribi un Post (Grupo de usuarios de .NET en Madrid) avisando de la creacion del grupo de usuarios de .NET en Madrid MAD.NUG.

Pues ahora quiero volver a felicitar a Miguel, amigo y compañero de trabajo, ya que ha sido recientemente nombrado MVP de C# en España.

Podeis ver su perfil MVP aqui

Creo que si le conocierais pensariais lo mismo que yo.... ENHORABUENA, TE LO MERECIAS!!

miércoles, enero 4

IsNumeric en C#

Hay muchas formas de hacer esto, pero creo que la mejor es usar Expresiones Regulares, ya que poner el tipico try{} catch{} con un Convert.To...() dentro funciona bien pero si falla la conversion penaliza mucho en performance, ya que lanzar una excepcion es algo muy pesado en .NET.

Os dejo el codigo que creo que se explica bien por si solo, aunque la verdad es que se ve fatal.
Faltaria incluir si quieren usarse o no separadores de miles.... pero creo que esto os dara la base para terminarlo, no?!

class NumericHelper
{
private const string regExNumericParse = @"^-{0,1}\d+$";
private const string regExNumericParseWithDot = @"^-{0,1}\d*\.{0,1}\d+$";
private const string regExNumericParseWithComma = @"^-{0,1}\d*\,{0,1}\d+$";

public static bool IsNumeric(string number)
{
return IsNumeric(number, ' ');
}

public static bool IsNumeric(string number, char decimalSeparator)
{
if (decimalSeparator != '.' && decimalSeparator != ',' && decimalSeparator != ' ')
{
throw new ArgumentException("decimalSeparator must be '.' or ','", "decimalSeparator");
}
switch (decimalSeparator)
{
case '.':
return Regex.IsMatch(number.Trim(), regExNumericParseWithDot);
case ',':
return Regex.IsMatch(number.Trim(), regExNumericParseWithComma);
case ' ':
return Regex.IsMatch(number.Trim(), regExNumericParse);
}
return false;
}
}

domingo, diciembre 18

Defensive programing in custom controls

Una de las Best Practices de todos los proyectos es tener tu propia coleccion de Custom Controls aunque a priori no vayamos a necesitarla. Basta con que heredemos de los controles del framework y cuando necesitemos implementar algo en todo nuestro proyecto veremos recompensada esta accion.

En mi proyecto tenemos todos los controles de la UI customizados y hemos ido añadiendo funcionalidad poco a poco, pero el otro dia me encontre un problema que os detallo a continuacion, asi como la solucion que elegimos para arreglarlo.

Muchas veces cuando creamos un control que va a usarse en todo nuestro proyecto no pensamos en todas posibles situaciones en las que este va a ser usado. Es imposible. Por motivos funcionales nos vimos obligados a añadir una serie de atributos a todos los controles, para diseñar un mecanismo que detectara en cliente si se habia modificado algun valor y poder preguntar asi al usuario si queria guardar los cambios antes de proceder a la navegacion hacia otra pagina de la aplicacion.

Pues nos pusimos manos a la obra. En nuestro CustomTextBox añadimos en el PreRender un atributo "onchange" que cambiaba el valos de un HiddenField marcando la pagina como "modificada".

Un mes mas tarde alguien necesitaba añadir cierta logica cliente para que, en un textbox determinado, al cambiar de valor, realizara una comprobacion de si este nuevo valor cumplia con una serie de restricciones. La persona encargada de esto hizo lo que tenia que hacer, añadio un atributo "onchange" a su textbox y la llamada a la funcion javascript que se habia creado, pero no le funcionaba. Despues de varias horas pensando que el problema era suyo, vino a hablar conmigo y vimos que su codigo era perfecto, el problema venia de mas arriba.

Al añadir en el PreRender del CustomTextBox el atributo "onchange" para el mecanismo de deteccion de cambios estabamos machacando cualquier otro atributo "onchange" que alguien, desde cualquier pagina de la aplicacion, quisiera añadir.

La solucion.

Despues de pensar en cual seria la mejor solucion para evitar esto hicimos lo siguiente. Antes de añadir cualquier atributo en cualquiera de nuestros Custom Controls decidimos chequear si ese atributo ya existia, y en ese caso, si el valor del atributo no era el mismo que queriamos añadir, lo concatenabamos para que se llamara a ambos.

Despues de ver que esto funcionaba perfectamente hicimos un pequeño refactoring para que quedara mas bonito y no tener codigo duplicado, creando un metodo del tipo AddAttributeSafety(string attibuteType, string attributeValue) que hacia todo lo que explicaba antes.

Solo una ultima cosa. Siempre que añadais un atributo para hacer cosas en cliente a un control, aseguraros de que terminais el codigo del valor del atributo con ";", porque si no no podreis concatenar mas de una accion sobre el mismo evento.

Este es el codigo del metodo para añadir atributos de forma segura en Custom Controls:

private void AddAttributeSafety(string attributeType, string attributeValue)
{
if (attributeType.Length == 0 attributeValue.Length == 0)
{
return;
}

if (Attributes[attributeType] == null Attributes[attributeType].Length == 0)
{
Attributes.Add(attributeType, attributeValue);
}
else
{
string existingAttribute = Attributes[attributeType];
if (existingAttribute.IndexOf(attributeValue) == -1)
{
Attributes.Add(attributeType, existingAttribute + attributeValue);
}
}
}



Como siempre espero que le sea util a alguien, y si se os curre algo mejor, compartirlo :D

jueves, diciembre 15

Cuidado con ListItemCollection.Insert()

Despues de un par de meses sin escribir nada vuelvo con otra de mis anecdotas.

En todos los controles que heredan de ListControl (DropDownList, ListBox...) , tenemos dos formas de añadir items de forma manual, que son:
- Items.Add(ListItem item);
- Items.Insert(int index, ListItem item);

Pues lo gracioso es que si intentamos añadir un ListItem que es null con el metodo Add(), nos lanza una excepcion, pero si usamos el metodo Insert() la excepcion no se lanza al añadir el ListItem nulo, si no que se lanza al renderizar la pagina.

Ademas, si nos fijamos en la Propiedad SelectedIndex (que si no hay ningun item seleccionado deberia valer -1), vemos que es null, asi que si intentamos acceder a ella tambien lanza una excepcion.

¿Por que se comportan de distinta manera estos dos metodos? ¿Deberia lanzar una excepcion el Insert() igual que lo hace el Add()?

La verdad es que no deberiamos de insertar nunca un ListItem que sea null, pero visto lo visto no viene mal algo de defensive programing:
- Si el ListItem nos lo devuelve un Metodo, antes de insertarlo chequear si es null.
- Si lo cogemos de Session con safetly cast (Session["myItem"] as ListItem) chequear si es null.
- Si lo hacemos a proposito aseguraros de hacer check in con el usuario del compañero que peor te caiga :D

La verdad es que no es un fallo muy dificil de detectar y si es muy raro que se produzca, pero como no a mi me ha pasado, y por eso escribo este post.

Espero que le sirva a alguien.

jueves, octubre 20

Restringir caracteres de un TextBox en cliente

Muchas veces queremos limitar la entrada de caracteres de un TextBox para permitir solo numeros.

Para evitar hacer PostBack, podemos realizar esta validacion en cliente de forma muy sencilla.

Al TextBox le añadimos el atributo "onKeyPress", que llamara a la funcion AllowJustNumbers();

Podemos hacerlo en el .aspx directamente o añadirlo desde el .cs de la siguiente forma.
txtRestringido.Attributes.Add("onKeyPress", "AllowJustNumbers();");

Metemos el siguiente script en el .aspx o en un .js aparte y listo.

function AllowJustNumbers()
{
if (window.event.keyCode <> 57)
{
window.event.keyCode = null;
}
}

Lo unico que hace este script es comprobar si la tecla pulsada esta entre el 0-9, y si no pone la tecla pulsada a null y asi no la metera en el textbox, es como si nunca se hubiera pulsado esa tecla.

P.D. 48 y 57 son los codigos ASCII asociados al 0 y al 9.

Esta tecnica se puede escalar para limitar la entrada de cualquier caractes, solo teneis que coger el ASCII y añadir una nueva condicion al if.

Un saludo,
Dani