Oficina virtual de Correos.es: la odisea de usar una aplicación mal hecha

Ya he hablado en otras ocasiones de aplicaciones Web de gran impacto y que están rematadamente mal hechas y sin pensar en el usuario. Ésta vez me toca hablar de la Oficina Virtual de Correos.es, el operador nacional de correo en España.

Hace unos días tuve que enviar un Burofax y me dije: «Ya que esta gente tiene una oficina on-line que incluso ha llevado premios, vamos a hacerlo directamente por Internet, que será coser y cantar«. ¡Qué error cometí!.

El problema más grave fue sin duda el que se refiere a los pagos on-line. Resulta que estableces los parámetros del servicio que quieres utilizar y cuando ya lo tienes en el carrito de la compra te da la opción depagarlo on-line inmediatamente. Para ello debes introducir el número de tu tarjeta de crédito y, en teoría, se procesa el pago y el servicio queda listo para ser gestionado or un atento funcionario (perdón, ahora desde que no son monopolio del Estado son «personal laboral fijo»,aunque algún funcionario queda). El problema es que tras introducir los datos de la tarjeta y continuar te sale un mensaje diciendo que la tarjeta tiene un problema y no se ha podido cargar el importe en la misma. «¡Qué raro!, pero si yo pago muchísimas cosas con esta tarjeta sin problema«, pensé. Así que lo que hice fué intentarlo con otra diferente. Mismo resultado. Y finalmente con una tercera y mismo resultado. El problema es que de repente me entran los SMS avisándome de los cargos en las tarjetas. «¿Cómo?, pero si no me lo podían cargar y aquí sigue pendiente el pago«. Llamo al teléfono del banco de Correos (que amablemente facilitaban en el mensaje de error), y me confirman que los cargos sí que han tenido éxito y que en realidad aunque el servicio figuraba como «no pagado» ¡me lo habían cobrado tres veces!.

Increible. Lo peor es que según la operadora que me atendió recibían muchas llamadas como la mía porque le pasaba a todo el mundo y que Correos lo sabía desde al menos hacía una semana. Para denunciarlos :-(((

Al final llamé a soporte técnico de Correos y tuve la suerte de que me tocó (a la segunda, porque la primera vez me dijeron que igual «era un virus o algo» o «que estaba entrando mucha gente») una chica muy espabilada y atenta que sabía de lo que estaba hablando anulé el pedido y a los pocos días me devolvieron el dinero en las tres tarjetas. Por supuesto, tuve que ir a una oficia física a poner el Burofax, con el correspondiente tiempo perdido sumado a la más de una hora que perdí intentándolo por Internet. Y luego quieren acercar la administración al ciudadano :-(((

De todos modos aproveché y saqué algunas conclusiones sobre la aplicación Web de Correos.es que merece la pena compartir.

Primeramente: la aplicación está hecha con ASP.NET 1.1 (al menos le tienen aplicado el Service Pack 1, menos da una piedra):

¿Y cómo lo sé? Pues como se puede observar por la captura, la aplicación rompe bastante, y cuando lo hace muestra todos los detalles de los errores. Esta es la primera mala práctica de seguridad que todo programador mínimamente decente de .NET tiene que saber: No se pueden mostrar los errores detallados a los usuarios. De hecho para hacerlo hay que cambiar a propósito el web.config, así que para mi aún tiene más delito que otros errores. Es más, el hecho de que no haya una página especialmente creada para gestionar estos problemas de manera elegante denota una gran falta de esmero a la hora de hacer la aplicación. Y por supuesto revela que la aplicación no está instrumentada y que probablemente nadie se entera de los errores, y si te dedicas toda la tarde a echar abajo la aplicaicón o a saltarte la seguridad, nadie hará nada por evitarlo.

Deben de mezclar alguna aplicación antigua con las páginas de esta porque de vez en cuando te saltan errores (por supuesto también visibles) que hacen referencia a VBScript, o sea, a ASP 3.0 Clásico:

Lo peor es que estos errores a veces te dan pistas sobre la estructura de disco del servidor y facilitan mucho al que quiera entrar como Pedro por su casa:

De vez en cuando la aplicación pierde la sesión, y en lugar de comprobarlo y obligarte a autenticarte de nuevo, pasan cosas como esta:

O sea, te salen las plantillas de los controles vacíos. Mola ¿no? 😉

Por fin el peor de los errores (aparte del de mostrar los mensajes de error detallados) que vi en el rato que estuve: deben de tener un Web Farm o un Web Garden para atender a las peticiones y lo tienen mal configurado, por lo que cada dos por tres al pulsar un enlace para ir a otra página te sale esta bonita página de error:

O sea, ¿el que montó esto no sabía que cuando varios servidores atienden las peticiones de una aplicación web deben tener las claves de máquina sincronizadas para evitar que falle la validación del ViewState, las cookies de autenticación, etc?. Una coña marinera.

Cuanto daño hace el «body shopping» de algunas consultoras :-(((

¿Y sabeis lo peor del caso? Que como se ve que no están muy contentos con la aplicación, hace ya más de un año sacaron a concurso el hacer una nueva en Java/J2EE. Claro, seguro que algún iluminado dentro de la empresa dijo «Esto no vale para nada. Vamos a tirar a la basura la millonada que hemos gastado en la anterior y vamos a hacer una nueva. Eso sí, la próxima la quiero en J2EE y con Oracle, que esto de .NET es una mierda, ya lo veis». Claro, probablemente no habrán pensado que la tecnología es lo de menos si la gente que la utiliza no sabe cómo utilizarla bien. De momento no hay nada en J2EE así que ya veremos cuando la sustituyan. O ¿se habrán echado atrás en el último momento?.

En fin, siento la longitud y la acritud que refleja de este post, pero es que hay cosas con las que no puedo.  A una empresa pequeña no le pasan ni la mitad de lo que le pasan a estas empresas grandes pseudo-monopolistas 🙁

Otro día os hablaré de otras, que ejemplos hay muchísimos.

ASP.NET: Controlar el uso de la caché de salida (OutputCache) de una página

La semana pasada os contaba en un post la forma de eliminar la caché de salida de una página a voluntad, antes de que caduque de manera «natural», usando el método RemoveOutputCacheItem. Este método tiene el problema de que debemos hacerlo desde una página diferente a la que está cacheada, porque en ésta los eventos de servidor (incluyendo el click de un botón) no saltan. Además dejé planteado un caso relativamente común que se puede dar y en el que resultaría útil disponer de otra forma de controlar si se hace caché o no.


Imagina esta situación: tienes una página en caché que los usuarios normales pueden ver pero no editar, pero que los administradores pueden cambiar usando los botones apropiados. Si simplemente activas la caché para que los usuarios vean la versión cacheada de la página, como hemos visto, ninguno de los eventos normales saltará, así que los administradores tampoco podrán editar nada, ni tampoco se verán los cambios que han hecho hasta que la caché se refresque. ¿Cómo podemos conseguir que la caché salte únicamente para los usuarios normales, pero que para los editores o administradores la página funcione con normalidad?


La primera tentación es pensar en hacer caché de la página con un VaryByCustom, que guarde en caché una versión diferente de la salida página según quien sea el usuario actualmente autenticado en el sistema. Esto está bien excepto por un pequeño problema: que aunque sí serviría para crear una versión diferente en caché de la página por cada tipo de usuario (o el criterio que elijamos), no nos permite no hacer caché. Es decir, no podemos anularla por ejemplo para los administradores y hacerla para el resto de perfiles, que es lo que buscábamos. Así que este camino es un punto muerto.


La técnica para conseguirlo pasa por el uso de un evento especial de la caché que es llamado automáticamente una vez en cada petición. Para ello disponemos del método AddValidationCallback. Éste toma como argumentos la referencia a un delegado del tipo HttpCacheValidateHandler, y un objeto cualquiera que sirve para pasar los datos que necesitemos a la llamada (normalmente lo usaremos con una referencia nula).


Así, en el evento de carga de la página pondremos este código:



Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    lblHora.Text = DateTime.Now.ToLongTimeString()
    If User.Identity.IsAuthenticated Then
       
Response.Cache.AddValidationCallback(New HttpCacheValidateHandler(AddressOf ValidateCache), Nothing)
    End If
End Sub


El evento Load saltará siempre que la página no esté en Caché, es decir, la primera vez que llamemos a la página. En este caso lo que hacemos es que si el usuario actual está autenticado, asignamos la función ValidateCache como la responsable de decidir en cada petición la validez de la caché actual de la página.


Ahora sólo resta definir el manejador del evento, que será como este:



Public Shared Sub ValidateCache(ByVal Currentcontext As HttpContext, ByVal data As Object, _
ByRef status As HttpValidationStatus)

    If
Currentcontext.User.IsInRole(«Administradores») Then
        status = HttpValidationStatus.IgnoreThisRequest
    Else
        status = HttpValidationStatus.Valid
    End If

End Sub


Lo que se hace es comprobar si el usuario actual está dentro del rol de «Administradores», en cuyo casi devolvemos como estátus de validación de caché el valor IgnoreThisRequest de la enumeración HttpValidationStatus. Al hacer esto lo que conseguimos es que se obvie la caché para la página, y por lo tanto ésta se ejecute normalmente.


Si el usuario es cualquier otro tipo de usuario validamos la caché (con el valor Valid de la misma enumeración) de forma que ésta actuará de la manera habitual.


Con esto conseguimos el efecto buscado que es que la caché se realice para todos los usuarios excepto para los administradores, de foram que puedan trabajar en ella normalmente.


En un programa real iríamos un paso más allá e invalidaríamos la caché de la página con la técnica aprendida en el post anterior siempre que un administrador cambiara algún dato en la página, dando acceso inmediato a la nueva versión a todos los usuarios.


Aunque antes he dicho que cuando la página está en caché los eventos de ésta no saltan, éste evento de validación saltará siempre (en todas las peticiones) porque no es se trata de un evento de la página, sino un evento de la propia caché, y por lo tanto ajeno al ciclo de vido de la página (pero no al ciclo de vida de una petición). No te dejes engañar por el hecho de que el código del evento esté en la propia página.


Una sutileza más


Antes de dar por terminado el post. La enumeración HttpValidationStatus aún tiene un valor más aparte de los dos que acabamos de ver. Se trata del valor HttpValidationStatus.Invalid. Si utilizamos este valor en lugar de HttpValidationStatus.IgnoreThisRequest, como en el ejemplo, aparentemente la técnica funcionará igual, pues se saltará la caché para los administradores y permitirá que estos trabajen en la página con todos sus eventos. 


Sin embargo hay una diferencia importante: cuando usamos HttpValidationStatus.IgnoreThisRequest lo que conseguimos es saltarnos el uso de la caché, de forma que la página se ejecuta normalmente y la caché existente no se ve afectada, quedando intacta para el resto de los usuarios. Sin embargo cuando usamos el valor HttpValidationStatus.Invalid lo que indicamos es que la caché actual ya no vale (lo que técnicamente se conoce como «fallo de caché» o «cahé miss» e inglés), y por lo tanto el efecto conseguido es que se elimina la caché que existiera en ese momento para la página, se ejecuta ésta y se genera una nueva versión cacheada de la misma.


La diferencia es tremenda. En el primer caso nos la saltamos sin afectarla, pero en el segundo lo que hacemos es generar una versión nueva para todos los usuarios, con las implicaciones de rendimiento y posible visualización de información consistente que ello implica. Así que hay que tenerlo en cuenta.


Obviamente podemo usar HttpValidationStatus.Invalid para borrar la caché en casos que realmente así lo requieran, pero hay que tener en cuenta los posibles efectos.


Este tema está realmente pobremente documentado y es muy poco conocido, así que espero que te resulte de utilidad 🙂

40 años de UNIX

Sí, el sistema operativo que nunca has querido usar cumple 40 años 😉

Como seguro que sabes, UNIX es la base de todas las distribuciones de Linux, pero ¿sabías que Mac OS X está basado también en este sistema operativo?. Obviamente también es la base de otros sistemas como Solaris, Irix, AIX, o BSD. Y ¿sabías que el UNIX con mayor implantación era de Microsoft?. Se llamaba Xenix, y antes de que llegara Linux fue el que tuvo un mayor número de usuarios.

Puedes saberlo todo sobre la historia de UNIX y sus creadores, los míticos Ken Thomson y Dennis Ritchie en la entrada de UNIX de la Wikipedia.

En realidad se podría decir que, a pesar de la aparente variedad, el mundo de los sistemas operativos se divide en dos: Microsoft Windows y los derivados de UNIX.

El famosísimo gurú Joel Spolsky ha afirmado lo siguiente:

«¿Cuáles son las diferencias culturales entre los programadores de Unix y de Windows?. Existen muchos detalles y sutilezas, pero en su mayor parte se resumen en una sola cosa: la cultura Unix valora el código que es útil para otros programadores, mientras que la cultura Windows valora el código que es útil para los que no son programadores. Esto es, por supuesto, una gran simplificación pero, en realidad, esta es la gran diferencia: ¿Estamos programando para otros programadores o para los usuarios finales?. Todo lo demás son comentarios.«

Parece que últimamente los chicos de Linux, al menos en algunas de sus distribuciones, están haciendo un buen trabajo para cambiar esta cultura. Eso es bueno: la competencia fomenta la innovación y la mejora, y es bueno para los usuarios.

¡Felicidades de corazón por este aniversario!

Nuevo libro de Krasis Press: Workflows en Sharepoint

Esta noticia es de hace un mes y con la vida ajetreada que llevo últimamente casi se me pasa ponerla en el blog (parece mentira) 🙂

Ha pasado una buena temporada, pero al fin tenemos aquí un nuevo libro de Krasis Press. Se trata de «Workflows and Sharepoint: Going with the Flow».

No, no es que se nos haya «ido la pinza» usando anglicismos en el título, es que se trata de nuestro primer libro en inglés.

Lo ha escrito Gustavo Vélez, uno de los mayores expertos mundiales en Sharepoint. Gustavo es ingeniero mecánico y electrónico, director de soluciones en Avanade en Holanda y ha trabajado con Sharepoint desde antes incluso de que se llamase así. Podemos leer artículos suyos en varias de las revistas más importantes del sector, publicadas en inglés, alemán y español. Como ves todo muy internacional 🙂 Es webmaster de SkunkWorks, el único sitio en español íntegramente dedicado a Sharepoint, y le han concedido el premio MVP en tecnologías Sharepoint MOSS.

El libro es una referencia accesible para guiar paso a paso a los usuarios a través del proceso de creación de workflows en Sharepoint. Se basa en ejemplos claros para describir y poner de manifiesto sus posibilidades y aplicaciones. Se ha dividido en cinco áreas para una fácil consulta:

· Introducción a la arquitectura y al uso de workflows
· Uso de SharePoint Designer para crear flujos sin tener que programar
· Creación de flujos “Sequential” y “State-Machine” utilizando Visual Studio
· Creación y desarrollo de formularios
· Activities, su uso en Visual Studio y en SharePoint Designer, otros aspectos avanzados de la programación de workflows en SharePoint.

Si estás en España cómpralo en nuestra tienda con gastos de envío por mensajería urgente incluídos en el precio.

Si estás fuera de España puedes comprarlo directamente en:
Buy at Amazon Buy at Barnes & Noble 

ASP.NET: Cómo eliminar la caché de salida (OutputCache) una página o control

Los que me conocéis o habéis ido a alguna de mis charlas sabéis que soy un gran defensor de las técnicas de Caché de salida en las páginas para mejorar el rendimiento y la respuesta de las aplicaciones. De hecho en este blog he hablado ya bastantes veces sobre la Caché en sus diversas variantes. Así que quizá resulte chocante que hoy vaya a hablar sobre justo lo contrario: cómo eliminar la caché de salida (OutputCache) de una página.


Como es sabido, para habilitar la caché de salida de una página o control lo único que tenemos que hacer es añadir una directiva similar a esta al  principio de la página, justo tras la directiva de página:


<%@ OutputCache Duration=»60″ VaryByParam=»None» %>


Los parámetros que se pueden usar son variados y no voy a entrar aquí en detalles pues todo programador de ASP.NET debe conocerlos (si alguien necesita formación sobre desarrollo web, ya sabe ;-)). Es posible hacer caché de la página completa, sólo de algunas partes, de todo menos algunos puntos concretos, que la caché dependa de cualquier parámetro o control, de una variable de QueryString, etc… Incluso definir nuestra propia política de cacheado en función de lo que queramos. En fin, una maravilla, fácil de usar y con resultados espectaculares cuando se aplica juiciosamente.


Pero, como toda herramienta, se puede volver en nuestra contra en un momento dado. ¿Qué pasa si algo ha cambiado y necesitamos que una determinada página -cacheada por un buen rato- se actualice inmediatamente con nueva visualización? En este caso necesitaremos que la caché de la página se elimine de inmediato. Es posible crear una dependencia de caché para que ésta dependa de un archivo, una consulta a una base de datos o casi cualquier otro recurso, pero en ocasiones querremos hacer algo más sencillo.


Luego veremos un caso mucho más claro de porqué queremos borrar este tipo de caché, pero primero quiero ver un caso más simple y su solución, más fácil también.


En el caso de simplemente querer eliminar la caché para una página la solución es bastante sencilla, si bien poco conocida por parte de los programadores de ASP.NET. La clase HttpResponse ofrece un método que sirve precisamente para eso: RemoveOutputCacheItem.


El único parámetro que necesita este método es la ruta absoluta virtual (es decir, empezando por «/») de la página cuya caché queremos liberar. Así, por ejemlo, para liberar la caché de la página actual haríamos lo siguiente:



HttpResponse.RemoveOutputCacheItem(Request.CurrentExecutionFilePath)


Esto en teoría, claro, porque lo primero que hará la mayoría es correar a una página de pruebas, habilitar la caché y poner un botón que haga lo de la línea anterior. El resultado: ¡no le va a funcionar!


El motivo es que, una vez que cacheamos la página completa, al llamarla de nuevo, incluso al pulsar un botón, ésta se saca directamente de la caché y su ciclo de vida normal no se ejecuta, por lo tanto no le funcionarán los eventos. Para conseguirlo con este método es necesario hacer la llamada desde otra página (luego explicaré cómo conseguirlo en la misma página con otro método).


En este archivo (3,95Kb) he incluido una página que, cuando es accedida desde cualquier otra, invalida la caché de ésta primera (en caso de haberla). Así, para eliminar la caché de cualquier página sólo es necesario colocar un enlace a BorraCache.aspx en ella y listo, con este código: 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
‘Obtengo la página desde la que he llegado aquí
Dim uriAnterior As Uri = Request.UrlReferrer
If Not uriAnterior Is Nothing Then
Dim sRuta As String = uriAnterior.AbsolutePath
HttpResponse.RemoveOutputCacheItem(sRuta)
lblInfo.Text = «Se ha borrado la caché de la página « + sRuta
Else
lblInfo.Text = «Esta página no puede ser llamada directamente. Llámala desde una página cacheada para eliminarla de la caché de salida.»
End If
End Sub

Obviamente es una prueba de concepto, y en una aplicación real no deberíamos incluirla de esta manera pues podría llamarla cualquiera para eliminar nuestra aplicación, pero sirve para captar la idea y poder usarla, por ejemplo, desde una página de administración protegida.


En el próximo post voy a continuar con este tema y a explicar algo mucho más interesante: Cómo eliminar selectivamente la caché de la página actual.


Imagina esta situación: tienes una página en caché que los usuarios normales pueden ver pero no editar, pero que los administradores puedes cambiar usando los botones apropiados. Si simplemente activas la caché, como hemos visto, ninguno de los eventos normales saltará, así que los administradores tampoco podrán editar nada, ni tampoco se verán los cambios que han hecho hasta que la caché se refresque.


En el próximo post veremos cómo conseguir esto.

Video en Channel9: mantenimiento de sesiones en ASP.NET

Los que vísteis hace unas semanas mi vídeo sobre mantenimiento de sesiones en operaciones largas de cliente con ASP.NET seguro que os interesa saber que ahora podéis verlo a alta calidad y descargarlo en diversos formatos para su estudio pormenorizado. Microsoft lo ha publicado en Channel9 así que podéis verlo ahora también aquí:


http://channel9.msdn.com/posts/Daniel+Garzon/Mantenimiento-de-Sesiones/


El código de ejemplo se puede descargar desde el post de mi blog referenciado en el primer enlace.


Espero que os resulte útil 🙂