lunes, enero 07, 2008

ASP en capas: obtener valores por QueryString

Vamos a comenzar a desarrollar la aplicación que mencionamos en el post anterior, y como queremos hacerlo con estilo, vamos a necesitar un poco de abstracción.

Lo primero que necesitamos es una forma para obtener valores desde "QueryString". Hace un tiempo comentamos como obtener valores por QueryString en .NET, ahora necesitamos hacerlo en ASP.

Hace algún tiempo construí la clase clsRequester para obtener valores por los tres métodos: querystring, form y cookie. Lo más importante de esta clase es que, al llamar a alguno de sus tres métodos públicos, debemos proporcionar un valor por defecto que será el resultado de la función cuando el obtenido no sea válido o no exista. Este valor por defecto debe ser del subtipo que esperamos conseguir (Integer, Byte, String, Date, etc).

Los métodos públicos de la clase clsRequester son:

public function Obtener(byval metodo, byval key, byval def)
Este método obtiene el valor de "key" por el "metodo" indicado. El dato obtenido se intenta convertir al subtipo de dato de "def". En caso de error se devuelve "def".
Ej: p = objRequester.Obtener("QueryString", "pagina", cint(1))

public function ObtenerB(byval metodo, byval key, byval def, byval min, byval max)
Obtiene el valor de "key" por el "metodo" indicado pero valida que dicho valor se encuentre entre un valor mínimo y un máximo (la B de ObtenerB es por Between). En caso de error o superar los límites, devuelve "def".
Ej: p = objRequester.ObtenerB("Cookie", "BirthDate", cdate("1901-01-01"), cdate("1910-01-01"), cdate("2000-12-31"))
Obtiene el de la cookie "BirthDate" y verifica que este comprendida entre las fechas indicadas. En caso de error devuelve la fecha 1 de enero del 1901.

public function ObtenerR(byval metodo, byval key, byval def, byval regex)
Obtiene el valor de "key" por el "metodo" indicado y lo valida con una Regular Expression. Este método es, por supuesto, para obtener "strings".
Ej: p = objRequester.ObtenerR("Form", "email", "", "\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")
En este ejemplo, el email debe ser validado por la Reqular Expression, en caso contrario devuelve un string vacío.

Los métodos privados son:

Private Sub Class_Initialize
Para inicializar las variables.

Private Sub Class_Terminate
Si usamos un objeto Regular Expression lo destruye.

private sub MetodoDefault(byval metodo)
Verifica que exista el método indicado exista.

private function getValue(byval metodo, byval key)
Obtiene el valor por el método indicado.

private function Castear(byref dato, byval def)
Convierte el valor obtenido al subtipo del valor por defecto.

private Function ValidaExpresionesRegulares(ByVal texto, ByVal patron)
Valida el valor con la Regular Expression

Esta clase la utilizo en cada una de las aplicaciones que debo construir en ASP.
Aquí les dejo la clase Requester para que se la puedan bajar.

martes, diciembre 25, 2007

ASP en capas

Una de las cosas que me gustan del lenguaje ASP es que, como no tiene más actualizaciones desde 2001, mi conocimiento sigue siendo válido aún cuando hace tiempo que no lo uso ;)

Me sorprendí mucho al entrarme de que, aún hoy, mucha gente sigue desarrollando en ASP. He recibido muchos comentarios acerca de la nota que escribí aquí mismo hace un tiempo sobre "Separación en capas" pidiéndome ejemplos en ASP.

ASP no es un lenguaje demasiado elegante, pero igualmente podemos desarrollar con estilo.

En las siguientes notas vamos a ver los requisitos para desarrollar en capas con ASP y finalizaremos con un ejemplo utilizando todos los elementos mencionados.

Lo que vamos a lograr es separar nuestro código en las siguientes capas:
  • Capa de presentación: optimizada para mostrar datos rapidamente.
  • Capa de negocio: donde se define el qué y el cuando.
  • Capa de datos: que sabe como almacenar y recuperar datos.
La aplicación que vamos a desarrollar es una página simple que muestre un "drop down" de categorías y, al seleccionar alguna, veremos un listado de elementos. Vamos a tener en cuenta todas aquellas cosas que mencionamos en posts anteriores como:

jueves, noviembre 01, 2007

Los efectos de la publicidad online

Un estudio realizado con diferentes tipos de publicidad online, buscando datos sobre la sensación de intrución sobre los usuarios y sus efectos, arrojó resultados muy interesantes.
  • El tipo de publicidad "pop-under" resulta intrusivo para el 28%
  • Los "pop-ups" resultaron intrusivos para el 26,1% de las personas
  • Los inline banners son intrusivos para el 21,1%
Otra forma de leer estos números sería remarcar que los popups resultan un 24% y los pop-under un 33,1 más intrusivos que la publicidad inline.

Un dato adicional es que esta percepción no varía significativamente si la publicidad tiene o no relación con el contenido de los sitios.

En todos los casos, a mayor intrución, menor es la intención de regresar al sitio visitado.

Fuente: Communications of the ACM, March 2007

martes, octubre 16, 2007

GeoIP WebService con ASP.NET y C#

Para este ejemplo me enfoqué en los elementos necesarios para crear un WebService en ASP.NET para obtener el país de origen de una IP. Por este motivo deben tener en cuenta que temas como separación de capas, administración de errores, configuraciones en web.config y otras cosas muy importantes deberán ser implementadas por ustedes.

Este ejemplo consta de una sola página .asmx y, aunque no es lo recomendado, debo admitir que hay veces en las que me gusta que toda la solución pueda ser fácilmente portada copiando un solo archivo.

Con todas estas salvedades, pasemos a la receta.

Ingredientes
  • Una base de datos de IP. Recomiendo la de MaxMind - GeoLite Country / Open Source IP Address to Country Database. Para este ejemplo elegimos la versión gratuita.
  • Una base de datos de una sola tabla. Para este ejemplo elegimos Microsoft Access para hacer el ejemplo más sencillo y transportable.
  • Una Regular Expression para validar IPs.
  • Un algoritmo para convertir un string IP en un double.

Preparación
1.- Nos bajamos la base gratuita de IPs desde la página de MaxMind (para una solución comercial deberíamos adquirir la versión full) desde haciendo “clic aquí”.

2.- Creamos una nueva base de datos Access y creamos una tabla que llamaremos “IPSegments”. Esta tabla deberá contener los siguientes campos (si respetamos el orden será luego más fácil importar la base).
  • beginIP – Text
  • endIp – Text
  • beginNro – Numbrer (double)
  • endNro – Numbrer (double)
  • CountryCode – Text
  • ContryName - Text
3.- Importamos la base de IPs a la base que creamos en Access. Para este ejemplo la base debe estar en la misma carpeta del Web Server donde estará nuestro Webservice.

4.- Creamos nuestro archivo .asmx.
Luego de la declaración de WebService nos aseguramos de incluir las siguientes líneas “using”:
using System.Data;
using System.Data.OleDb;
using System.Text.RegularExpressions;

El único método web será algo así:
[WebMethod]
public string GetCountryCode(string ip) {
return GetCountryByIp(ip);
}


El primer método privado será el validador de IPs. Lo podemos resolver de forma elegante con una Regular Expression.
private bool IsValidIp(string ip) {
string pattern = @"^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$";
Regex reg = new Regex(pattern, RegexOptions.Singleline | RegexOptions.ExplicitCapture);
return reg.IsMatch(ip);
}


Luego necesitamos el algoritmo para convertir una IP en un double
private double Ip2Double(string ip) {
string[] octetos = ip.Split('.');
int w = int.Parse(octetos[0]);
int x = int.Parse(octetos[1]);
int y = int.Parse(octetos[2]);
int z = int.Parse(octetos[3]);

double result = 16777216 * (double)w + 65536 * (double)x + 256 * (double)y + (double)z;
return result;
}


Finalmente creamos el método que busca el país en la base de datos
private string GetCountryByIp(string ip) {
if (!IsValidIp(ip)) throw new Exception("Invalid IP format");

object result;
double ipNum = Ip2Double(ip);
string connectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=";
connectionString += System.Web.HttpContext.Current.Server.MapPath("GeoIPCountry.mdb");

OleDbConnection oConn = new OleDbConnection(connectionString);
string query = "SELECT CountryCode FROM IPSegments WHERE @IpNum BETWEEN beginNro AND endNro";
OleDbCommand dbCommand = new OleDbCommand(query, oConn);
dbCommand.Parameters.Add("@IpNum", DbType.Double).Value = ipNum;

oConn.Open();
try {
result = dbCommand.ExecuteScalar();
} finally {
oConn.Close();
}

if (result == null) throw new Exception("IP not in Database, maybe is a local IP");
return result.ToString();
}


En este link tienen el “plato terminado”: GeoIP WebService con ASP.NET y C#. Pueden copiarlo en una instancia de IIS configurada para ejecutar ASP.NET (funciona en todas las versiones) y probarlo. Sin embargo les recomiendo hacer sus propias implementaciones tomando este ejemplo solo como una especie de “starter kit”.

lunes, agosto 13, 2007

Desarrollando aplicaciones


Desde hace unos años que mi trabajo diario no consiste en escribir código. Sin embargo continúo participando del proceso de desarrollo de aplicaciones.

Uno de los errores más comunes que noto entre los programadores es la idea de que desarrollar una aplicación es escribir su código.

Muchas veces, cuando desarrollamos una aplicación pequeña, y que es similar a otras tantas que hemos hecho previamente, nos sentamos frente al teclado y hacemos el análisis y el código casi al mismo tiempo. Aún en estos momentos primero analizamos y luego codificamos.

Codificar, compilar, debugear e implementar es sólo una parte del trabajo. De hecho es la segunda parte y, probablemente, nos insuma cerca de la mitad del tiempo que necesitamos para desarrollar una aplicación.

Gran parte del trabajo, muchas veces la que lleva más horas, la hacemos con papel y lápiz ó, como en la foto, con fibrón y pizarra.