Tag Archives: visual basic

Lenguajes de programación semánticos (python) contra matemáticos (c#)

Hace tiempo escribí un artículo en el que hablaba de frameworks web para programar y fui criticado por criticar django. Bueno como aclaratoria, escribo este artículo, en el que detallo las diferencias de los programadores, una gran batalla entre lenguajes semánticos vs matematicos; en este caso python vs c#.

Veamos primero que es cada uno, un lenguaje semántico es un lenguaje de programación que pretende ser similar a un lenguaje real, como el español, inglés, etc. mientras que un lenguaje matemático es mas parecido a ecuaciones con llaves, corchetes, paréntesis, etc. Pero veamos mas diferencias, un lenguaje semántico, sea cual sea, persigue el "de un vistazo", generalmente esta ausente de llaves y basa su estructuración en identación y estructuras muy semánticas como delimitadores de texto. Para este caso tenemos como ejemplo a VB, en el que terminamos un if con un End If, un for con un Next, etc. la identación automática que propone el propio ide de programación o como en el caso de Python, la identación es necesaria para que el interprete de Python entienda el código.

Un lenguaje matemático es en contra de un lenguaje semántico, un lenguaje de formulas y ecuaciones, que sin tener unas nociones de matemáticas y que estas nos gusten se nos pueden atragantar bastante. A diferencia de lo que ocurre en los lenguajes semánticos, este tipo de lenguajes a pesar de que la identación suele ser importante para la claridad y el entendimiento, también nos permite escribir todo nuestro código en una sola línea. Las funciones suelen estar delimitadas por llaves {} así como las clases y namespaces. Las lineas de un lenguaje matemático suelen estar delimitadas por puntos y coma ";", y como mencione antes, al tener delimitadores de linea todo el código puede estar en una única linea, como ocurre en el caso de los frameworks de javascript que comprimen su código hasta que ocupe una única linea.

¿Pero qué es mejor? Pues depende de la persona, igual que hay zapatillas para los corredores según su tipo de pisada, hay lenguajes según como programes. Hay programadores que son mas de letras, les gusta ver su código y creer que están leyendo un libro. Para ellos, un lenguaje semántico es ideal, un python o un visual basic. Para aquellos programadores que como me ocurre a mi, nos gusta ver una cierta simetría en nuestro código y que al ver el código parezca una libreta de un matemático, lleno de formulas, lenguajes como c# o java, son para mi.

¿Y cual es mejor? Pues ninguno. Lo mas importante es sentirse a gusto con el entorno con el que se trabaja. Si por ejemplo, eres un matemático puro, python es horrible, pero no quiere decir que no lo puedas utilizar. Por contra, si eres muy semántico, c# sería incomprensible. A la hora de trabajar, hay que tener en cuenta 3 factores básicos. En primer lugar en que lenguaje nos sentimos mas cómodos. Evidentemente no vamos a programar como no nos gusta (salvo que nuestro jefe nos lo diga). En segundo lugar hay que saber elegir bien el lenguaje con sus herramientas. En Lenguajes como PHP tenemos multitud de librerías y aplicaciones ya desarrolladas, en python django tenemos muchos módulos, etc. en c# el deploy es muy sencillo, pero no se nos ocurriría hacer una web en shell script por ejemplo, ya que no tenemos el mismo potencial de librerías. Por último hay que elegir sabiamente según lo que vayamos a hacer. Si por ejemplo vamos a desarrollar una pequeña aplicación, con un PHP vamos sobrados, si queremos generar una página sencilla, podemos utilizar django, pero si queremos hacer una aplicación grande y escalable, quizás c# nos convenga mas. Hay que saber equilibrar todo estos puntos para elegir siempre la mejor opción según lo que vayamos a desarrollar.

Yo programo las aplicaciones prefabricadas (wordpress, prestashop, etc) o páginas muy muy sencillas en PHP, otros proyectos a medida de mayor envergadura pero pequeños en python con django o pylons y los grandes proyectos en c# con mono aspnet mvc y AltairStudios.Core. Y tu, ¿En qué programas?

Deploy de ASP.Net MVC en Apache con mod_mono

Lo que voy a escribir aquí no es una guía de como instalar Mono ASP.Net con MVC sobre apache con mod_mono, aunque la escribiré, sino como hacer el deploy de una aplicación. Cuando montamos un sistema Mono ASP.Net con MVC sobre apache con mod_mono, hay que tener 3 cosas en cuenta para su correcto funcionamiento, son pequeños detalles pero que te pueden dar algún que otro quebradero de cabeza. Las 3 cosas a tener en cuenta son:

  • Apache no entiende que tu app es MVC, por lo que hay que decirselo.
  • Apache ni mod_mono son capaces de dictaminar tu index
  • Siempre hay que tener algo para recompilar el backend en caso de cacheo o fallo (generalmente cuando desarrollamos).

Bueno, expliquemos cada una, en primer lugar apache no sabe que tu app es un MVC de ASP.Net, por lo que cuando hagamos un deploy o creemos un proyecto nuevo de Mono ASP.Net con MVC, lo primero a crear es un .htaccess forzando a que es un MVC. El código del htaccess es:

ForceType application/x-asp-net

Con esto ya  podemos poner a funcionar nuestra aplicación web. El siguiente paso para hacer las cosas bien, sería crear un index, ¿Por qué? ¿Acaso no saben cual es mi index? Pues no, todas las pruebas, tanto en Linux como en Mac OS X, es que mod_mono no es capaz de entender cual es el index que definimos en el global.asax, por lo que lo mejor es crear un index.aspx que cargue nuestro HomeController, o el que queramos. El index estaría en el raiz del proyecto y su código sería:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<%
   this.Context.RewritePath("Home", false);

   IHttpHandler httpHandler = new MvcHttpHandler();
   httpHandler.ProcessRequest(this.Context);
%>

Lo que hacemos con este index.aspx es decirle que cuando cargue la home (el index) cargue automáticamente el HomeController. Ahora solo nos falta crear un sistema de reseteo de backend por si se queda en cache y queremos cambiar algo. Para ello creamos una carpeta, por ejemplo, reset-mono-backend y creamos un .htaccess dentro de esa carpeta. Cabe decir que al htaccess lo podemos otorgar de un sistema de autentificación y cosas por el estilo para acceder, pero como esto es un ejemplo, será lo más básico. El contenido del .htaccess será:

ForceType None
SetHandler mono-ctrl

Al entrar en /nuestroproyecto/reset-mono-backend, nos aparecerá una interfaz que nos permitirá entre otras cosas, resetear el backend. Otro día explicaré como se instala el sistema en si.

Habilitar sesiones en un handler.ashx con IRequiresSessionState e IReadOnlySessionState

En .Net, bien sea en C# o en VB.Net, hay un tipo de clases llamadas controladores genéricos que nos proveen de un nivel muy básico de controlador web. En ASP.Net, los handlers o  HttpHandler son un tipo de clases tan básicas, que no implementan entre otras cosas, las sesiones, por lo que tendremos que indicar explícitamente en la clase que tipo de sesión vamos a implementar.

Me voy a centrar en explicar 3 casos que son los más comunes, a la hora de implementar un handler:

  • Sin sesión: para esto no hay que hacer nada, con la declaración por defecto nos es suficiente. No tendremos acceso a la sesión, que sera nula si hacemos un context.Session
  • Sesión de solo lectura: para esto debemos implementar la interfaz IReadOnlySessionState, de tal modo que al hacer context.Session, tenga los valores de la sesión, pero no podremos añadir o actualizar datos sobre la sesión.
  • Sesión de lectura y escritura: para esto debemos implementar la interfaz IRequiresSessionState, que nos permitirá acceder a los datos de la sesión, así como añadir y actualizar los datos.
A continuación dejo unos ejemplos en C# y en VB.Net para que os hagais una idea.
[sourcecode language="csharp" title="Ejemplo de implementación de handlers en C#"] //Este ejemplo devolverá un error ya que context.Session es Nothing
public class IndalcasaSessionHandler : System.Web.IHttpHandler {
public void ProcessRequest(HttpContext context) {
Object value;

context.Session.Add("value", "un valor");
value = context.Session.Item("value");

context.Response.Write(value);
}
}

//Este ejemplo no devolverá un error ya que context.Session no es Nothing
//pero value tendrá el valor original que tuviera y no el valor "nuevo valor"
//ya que no se puede escribir en la sesión
public class IndalcasaSessionHandler : System.Web.IHttpHandler, System.Web.SessionState.IReadOnlySessionState {
public void ProcessRequest(HttpContext context) {
Object value;

context.Session.Add("value", "un valor");
value = context.Session.Item("value");

context.Response.Write(value);
}
}

//Este ejemplo no devolverá un error ya que context.Session no es Nothing
//y actualizará el valor de la sesión correctamente
public class IndalcasaSessionHandler : System.Web.IHttpHandler, System.Web.SessionState.IRequiresSessionState {
public void ProcessRequest(HttpContext context) {
Object value;

context.Session.Add("value", "un valor");
value = context.Session.Item("value");

context.Response.Write(value);
}
}
[/sourcecode] [sourcecode language="vb" title="Ejemplo de implementación de handlers en VB.Net"] 'Este ejemplo devolverá un error ya que context.Session es Nothing
Public Class IndalcasaSessionHandler
Implements System.Web.IHttpHandler

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim value As Object

context.Session.Add("value", "un valor")
value = context.Session.Item("value")

context.Response.Write(value)
End Sub
End Class

'Este ejemplo no devolverá un error ya que context.Session no es Nothing
'pero value tendrá el valor original que tuviera y no el valor "nuevo valor"
'ya que no se puede escribir en la sesión
Public Class IndalcasaSessionHandler
Implements System.Web.IHttpHandler, System.Web.SessionState.IReadOnlySessionState

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim value As Object

context.Session.Add("value", "nuevo valor")
value = context.Session.Item("value")

context.Response.Write(value)
End Sub
End Class

'Este ejemplo no devolverá un error ya que context.Session no es Nothing
'y actualizará el valor de la sesión correctamente
Public Class IndalcasaSessionHandler
Implements System.Web.IHttpHandler, System.Web.SessionState.IRequiresSessionState

Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim value As Object

context.Session.Add("value", "nuevo valor")
value = context.Session.Item("value")

context.Response.Write(value)
End Sub
End Class
[/sourcecode]

Espero que os saque de un apuro en el que alguna vez me he visto metido por no recordar las interfaces que hay que implementar para poder leer y/o escribir en la sesión en un controlador genérico de ASP.Net.

Por qué usar StringBuilder en lugar de concatenar Strings

Ando un poco liado y llevo una temporada sin escribir. Hay un apunte, que es común para varios lenguajes que son Java y por ejemplo .Net, tanto Visual Basic .Net y C#, así como el resto de lenguajes de la plataforma .Net que es la clase StringBuilder. Hay gente que no sabe por que o cuando utilizar la clase StringBuilder y realmente es uno de esos pequeños detalles de buenas prácticas, que a simple vista en un proyecto pequeño no se aprecian, pero cuando entre manos tenemos un gran proyecto que recibe millones de peticiones diarias, estas pequeñas nuevas practicas pueden suponer un gran referente de ahorro en el consumo de memoria y procesador de un servidor.

Tanto en Java como en .Net, cuando creamos un nuevo String, instanciamos un objeto String en una variable, cuando con la sentencia "+=" vamos concatenando mas texto, lo que hacen estas plataformas es crear una nueva instancia del objeto con la concatenación de las dos variables de texto. Por otro lado, cuando tenemos un StringBuilder instanciamos una clase StrringBuilder, llamando al método "append" en Java y "Append" en .Net, lo que hacemos es realizar una concatenación real de texto en el buffer de texto para luego instanciar un nuevo objeto String cuando llamemos al método "toString" en Java y "ToString" en .Net. A simple vista parece una tontería, cuando tenemos un texto que concatenamos 2 o 3 veces, realmente no merece la pena generar un StringBuilder, pero cuando concatenamos repetidamente texto varias veces el rendimiento es mayor si utilizamos StringBuilder, ya que si tenemos 20 concatenaciones seguidas, utilizando Strings normales concatenados, tendríamos 20 instancias de objetos, mientras que con StringBuilder solo 2. Como he dicho antes, en un pequeño proyecto, esto es prácticamente inapreciable, pero cuando tenemos un proyecto que recibe millones de peticiones diarias, algo tan tonto como utilizar concatenaciones de texto o StringBuilder puede suponer tener que añadir mas memoria al servidor para soportar tantas instancias de objetos e incluso un procesador mas potente para soportar el paso del recolector de basura para tantos objetos instanciados, esto en el mejor de los casos, si no llegamos al caso de tener que añadir un servidor al cluster para soportar todo esto.

Un cumulo de buenas practicas pueden suponer un gran ahorro de recursos, que se traducen en ahorro de dinero, cuando se trata de grandes proyectos.

Descodificar Quoted Printable para leer correos de GMail en Visual Basic

Un amigo esta realizando un proyecto en Visual Basic .Net, que entre otras cosas se conecta a GMail para recibir correos e introducirlos en una base de datos para mostrarlos en un panel de administración. Hasta aquí todo normal, el problema viene cuando en los correos utiliza caracteres, que vamos a llamar extraños, como tildes por ejemplo. Cuando recibimos por código un mail que por ejemplo contenía la cadena "conexión", este texto no se nos devuelve así, sino que nos devolvería "conexi=F3n" y he aqui el problema, ya que esto no es codificación normal de UTF-8 a ASCII o similares sino que es completamente diferente.

Los servidores de correo utilizan protocolos bastante antiguos, en los que todo se basta en texto. Para separar encabezados se utilizan saltos de linea tipo "rn" o "n" y por ejemplo para adjuntar archivos hay que declarar una marca y decirle que el contenido del archivo esta entre marca y marca. Como no, todo esta basado en texto ASCII por lo que los caracteres extraños, letras con acento, eñes y similares, suelen encontrarse en una codificación que se llama "Quoted printable".

Quoted Printable o simplemente acortado QP es un sistema de codificación de 8 bits compatible con ASCII que basa su codificación de caracteres extraños en un formato de un símbolo igual seguido de 2 posiciones hexadecimales. Se rige por el estándar RFC-1345. Aunque algunos lenguajes traen incorporado por defecto funciones o librerías para codificación y descodificación de caracteres, .Net no tiene nada para descodificar este tipo de codificación. A continuación os mostrare un ejemplo de función de Visual Basic para la descodificación de estos caracteres, que básicamente recoge estos caracteres hexadecimales, los convierte a entero y obtiene el caracter de ASCII extendido de 255 caracteres, no el tradicional de 128 caracteres. De esta forma, obtendrá el carácter correcto ya traducido. Os dejo el ejemplo de la función:

Función de descodificación de cadenas de texto Quoted Printable

Public Shared Function QuotedPrintableDecode(ByVal text As String) _
As String
  Dim i As Integer
  Dim DecodedString As StringBuilder
  Dim Chars As Char()
  Dim CharsValue As String
  Dim HexValue As Integer

  Chars = text.ToCharArray()
  DecodedString = New StringBuilder

  For i = 0 To Chars.Length - 1
    If Chars(i) = "=" Then
      CharsValue = Nothing
      HexValue = Nothing

      If Chars(i + 1) = "0" Then
        CharsValue = Chars(i + 2)
      Else
        CharsValue = Chars(i + 1) & Chars(i + 2)
      End If

      HexValue = Val("&H" & CharsValue)

      If CharsValue.ToUpper = Hex(HexValue) Then
        DecodedString.Append(ChrW(HexValue))
        i += 2
      Else
        DecodedString.Append(Chars(i))
      End If
    Else
      DecodedString.Append(Chars(i))
    End If
  Next

  Return DecodedString.ToString
End Function

Ahora solo hace falta llamar a esa función pasando la cadena a convertir:

Public Shared Sub Main()
  Dim text As String = "conexi=F3n"
  Console.WriteLine(Application.QuotedPrintableDecode(text))
End Sub

El resultado de aplicar esto seria la cadena "conexión". Para que funcione es necesario importar el namespace System.Text, pero solo para el StringBuilder

Imports System.Text

Espero que os sirva de ayuda.

Char curiosidad de IsLetter e IsDigit

El otro día, nos disponíamos mi jefe y yo a realizar un control sobre un campo de texto de una aplicación web. La idea era que en este campo solo se pudiera incluir texto o números, pero en ningún caso debería de poderse incluir caracteres raros. Seamos sinceros y siempre que hemos necesitado usar esto en lenguajes donde su framework no estaba preparado para diferenciar que tipo de carácter era, acabamos o bien creando un array diccionario y comparando los caracteres o bien usando expresiones regulares. Como no, desde el salto a tecnología de Microsoft (en este caso Visual Basic .Net) me propuse buscar alguna clase o método que hiciera solo lo que quería hacer, y la encontré.

En .Net existe la clase Char, que tiene el método Char.IsLetterOrDigit (boleano) donde le indicas un char o carácter y este te devuelve true o false si es un número o letra y false si no lo es. Monto una función para recorrer carácter a carácter del campo de texto comprobando si es alfanumérico o no, con la idea de borrar los caracteres que no sean alfanuméricos. Una vez montada la función, la pruebo unas cuantas veces y todo funciona estupendamente. Cuando nos vamos a disponer a subir a producción... sorpresa, la última prueba a fallado (pero es imposible), se nos deslizo el dedo y por poner un "1", pusimos un "º". Cuando nos ponemos a investigar (ha probar con jabatos) nos damos cuenta de que esta función, establece que los caracteres "º" y "ª" son alfanuméricos, vamos que son letras, supongo que la "o" y la "a".

Por supuesto esto lo controlamos y listo, pero si alguien se encuentra en nuestra misma situación y conoce alguna función que si trabaje correctamente que lo comente. Y si alguien buscando por internet se encuentra bloqueado y se ve encuentra con este post, ya puede respirar tranquilo, porque no es que funcione mal, es que no funciona del todo bien. (Si, ya se que para algunos "º" y "ª" son letras, pero realmente son caracteres especiales)

Bucle do-while en VisualBasic

Llevo tiempo currando con Visual Basic .Net, pero como persona formada desde hace años en lenguajes tipo C (C, C++, Java, C#, PHP, etc) el paso a programar en Visual Basic, cuesta mucho y cosas tan cotidianas como hacer un bucle, un switch o similares pueden convertirse en una peligrosa trampa que nos consumira muchos minutos muy valiosos.

La ultima que me he topado ha sido el bucle do while. En cualquier lenguaje tipo C, practicamente independiente del lenguaje estos bucles son iguales:

  do {
    sentencias
  } while(condicion);

Pero como no, estamos con Visual Basic y aqui todo funciona de manera diferente, es como nuestro tipico amigo que siempre lleva la contraria a todo. Por ejemplo para hacer un bucle do-while (me sorprende que en 9 meses sea la primera vez que me vea obligado a hacerlo, el bucle es do-loop-while, siendo su sintaxis

  Do
    sentencias
  Loop While condicionn

Puede que la gente que conozca o programe en Visual Basic lo vea una tonteria, pero para gente como yo que por razones laborales se ven obligadas a programar en dicho lenguaje y que por muchos meses se que lleve sigan prefiriendo C# a VB.Net, cosas tan cotidianas pueden convertirse en un minimundo.

Ya de paso y para aprovechar el post, explico que los bucles do while, son bucles que se recorreran igual que los while, en funcion de una condicion que de ser cierta dara una vuelta mas al bucle y que la principal diferencia entre los bucles while y do while, radica en que el while, primero comprueba la condicion antes de hacer una iteracion al bucle, mientras que los do while primero dara una iteracion al bucle y al final comprobara si debe de seguir haciendo iteraciones. Dicho de otro modo, el el while, primero comprobamos que debemos entrar al bucle y de ser cierto, entramos, en los do while, primero entramos al bucle y al final de este comprobamos si debemos dar una vuelta mas.