JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Server.GetLastError no funciona en IIS 7.0 o superior: cómo solucionarlo y un truco general para IIS 7.5

Si llevas unos cuantos años en esto del desarrollo Web seguro que tienes todavía aplicaciones por ahí escritas en ASP 3.0, también conocido como "ASP Clásico". Este precursor del actual ASP era estupendo y funciona de maravilla aún hoy en día. A pesar de todas las virguerías técnicas existentes en la actualidad (que me encantan) me confieso un enamorado de esa antigua plataforma.

El caso es que aún hoy en día, si tienes que montar una aplicación de ASP 3.0 incluso en un moderno Windows Server 2008 R2 con IIS 7.5, podrás hacerlo sin problemas y funcionará todo de maravilla. O casi...

El otro día tuvimos que montar una de nuestras aplicaciones "legacy" en este entorno precisamente y todo parecía ir de maravilla. El caso es que nosotros instrumentamos todas nuestras aplicaciones, incluso  las antiguas, para llevar un registro automático de todos los eventos de interés que se producen: avisos, advertencias, operaciones importantes sobre los datos... y por supuesto los errores no gestionados y por tanto inesperados. Se trata de una buena práctica que deberías seguir en cualquier aplicación, y más en una para Internet y de la cual algunos ya me habréis oído hablar en ponencias por ahí.

En ASP clásico la forma de gestionar los errores inesperados pasa necesariamente por personalizar la página de error para el estátus 500 del servidor Web con una página .asp propia. En ésta se obtiene información sobre el error producido usando el método Server.GetLastError que devuelve un objeto ASPError con todos los detalles.

La configuración en IIS 7.0 o IIS 7.5 se hace de la siguiente forma:

1.- En las propiedades del servidor virtual se va a la sección de páginas de error:

2.- Una vez dentro de ésta aparecen la lista de códigos de estátus HTTP estándar, como por ejemplo el 404 para páginas no encontradas (muy recomendable gestionarlo), el 302 (acceso denegado), o el que nos interesa: 50, error interno del servidor. Sustituimos la página por defecto de IIS para el error 500 y colocamos una página .asp propia. Utilizando el mencionado objeto ASPError podemos obtener información sobre errores que se produzcan, anotar información sobre lo que ha pasado con todo lujo de detalles (error, tipo, ubicación, página, usuario, tipo de navegador...) para luego poder hacer un diagnóstico y detectar problemas. También devolveremos una página más bonita y adecuada para los usuarios, lo cual es muy importante también, y además es una buena práctica de seguridad el no mostrar mensajes detallados de error al usuario final.

No funciona en IIS 7.x

La idea es estupenda y funciona muy bien si lo hacemos en IIS 5.0 o 6.0, ¡pero en IIS 7.x no funcionará!. Es decir, sí que se llamará a nuestra página personalizada, y ésta funcionará. El problema es que el método Server.GetLastError devolverá un objeto con todas sus propiedades vacías, por lo que sabremos que se produce un error pero no tendremos ni un sólo detalle del mismo :-(

Se trata de un bug reconocido por Microsoft desde IIS 7.0, pero que no ha sido corregido en ninguno de los Service Pack ni tampoco en la versión R2 del sistema operativo (nueva versión 7.5 de IIS). Son los riesgos de usar una tecnología antigua para la que Microsoft no tiene la menor intención de seguir invirtiendo ni un segundo.

¿Cómo lo solucionamos?

Como casi siempre hay una vía de escape para solventar el problema. IIS 7.x dispone de un gestor global de códigos de estado HTTP que se usa cuando no hay uno específicamente designado en la configuración. Resulta que en este gestor global de errores el objeto ASPError sí que se rellena correctamente.

Por lo tanto lo que tenemos que hacer es eliminar el estátus HTTP 500 de la lista de errores gestionados por IIS, para que no tenga asignada ni siquiera la página por defecto. Si editamos la configuración general de este módulo de gestión global de errores:

Nos aparece un diálogo en el que podremos ajustar nuestra página de gestión global:

Allí deberemos introducir una ruta relativa a la raíz de nuestra aplicación (por ejemplo "/Logevents/logerr.asp" como en la figura), y usar en el PathType la opción de "Ejecutar una URL".

De este modo se recibirán perfectamente las propiedades del error y podremos trabajar como siempre :-)

¡Uppps! IIS me da un error de "violación de bloqueo" (Lock Violation)

Vaya. Cuando ya pensábamos que lo teníamos controlado y podríamos tener nuestra aplicación ASP Clásico funcionando a pleno rendimiento, al pulsar "OK" en el diálogo de la figura anterior nos sale este mensaje:

¿Qué demonios es esto? La verdad es que el mensaje no proporciona demasiada información al respecto. He de confesar que cuando nos salio la primera vez pensé que era un bug de la interfaz de gestión de IIS 7.5, que tenía interbloqueos mal hechos ;-P

A base de indagar y probar, ya que no había información en Internet al respecto y la poca que hay no está bien, llegué a la solución del problema.

Por defecto, hay ciertas secciones de la configuración global de IIS 7.x que están protegidas para impedir la modifiación en sub-ramas del servidor. Esto está diseñado de esta forma pensando en las empresas de hosting, ya que de esta manera pueden bloquear ciertas secciones peligrosas para que los administradores de los sitios web que venden no puedan cambiar ajustes que puedan comprometer la seguridad global del servidor. ¡Bien hecho Microsoft!. Lo malo es que no está nada claro en ningún sitio (o al menos a mi eso me parece), y a más de uno que gestiona sus propios servidores le puede traer por la calle de la amargura. ¡Mal hecho Microsoft! ;-)

En nuestro caso lo que debemos hacer es desbloquear este ajuste en la configuración global del servidor para que nos permita cambiarlo en la configuración secundaria de los sitios Web.

Para ello debes ir, como administrador, a la carpeta "C:\Windows\System32\Inetsrv" o equivalente (está ahí incluso en versiones de 64 bits de Windows). Dentro de ésta encontrarás el archivo applicationHost.config. Sácale una copia por si acaso te cargas algo que no debes, y ábrelo con el bloc de notas, ya que es un simple archivo de texto XML.

Una vez abierto busca el nodo "<httpErrors>". Encontrarás una rama que pondrá algo similar a esto:

<httpErrors defaultPath="" defaultResponseMode="ExecuteURL"
lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">

La parte importante aquí es el atributo lockAttributes. Como puedes observar, por defecto, tiene bloqueada la modificación de la ruta por defecto para los errores, que es precisamente lo que pretendemos modificar en nuestro sitio web.

Elimina la palabra "defaultPath" del atributo lockAttributes, graba el archivo y ciérralo. Ahora vuelve a IIS y cambia d enuevo la configuración en el diálgoo que hemos visto. Esta vez, al cerrarlo, no te generará la violación de bloqueo, y todos felices.

Este último consejo te valdrá para IIS en general, y por lo tanto para ASP.NET o incluso PHP, y no se restringe sólo a esta sección de la configuración.

Espero que si llegas hasta aquí a través de un búsqueda, desesperado/a por el problema, todo esto te haya servido. Si me lo quieres agradecer puedes dejar un comentario, y también ya sabes ;-)

José Manuel Alarcón José Manuel Alarcón
Fundador de campusMVP.es, el proyecto de referencia en formación on-line para programadores en lengua española. Autor de varios libros y cientos de artículos. Galardonado como MVP de Microsoft desde 2004. Gallego de Vigo, amante de la ciencia y la tecnología, la música y la lectura. Ayudando a la gente en Internet desde 1996.
Descarga GRATIS mi último libro (no técnico): "Tres Monos, Diez Minutos".
Banner

Agregar comentario