viernes 23 de marzo de 2007

Rewriting en .NET II

Siguiendo con el tema, en esta segunda parte comenzaremos ya con el proceso completo, la configuración del IIS, y la captura de peticiones.

1. Proceso de generación del Rewriting
· Configuración del IIS
Paso básico para que funcione nuestro ReWriter. Partimos en la forma que trata el IIS las peticiones de recursos que le llegan.
Las páginas simples. Html, txt, pdf, etc. las sirve directamente sin pasar la petición al motor de .NET. Lo mismo ocurre para imágenes, gif, jpeg, etc. El servidor las buscará directamente y en caso de encontrarlas se las servirá directamente al cliente. Ya que vamos a controlas las peticiones directamente con el motor de .NET, es básico que cualquier recurso pedido pase por nuestras manos por si pudiese ser motivo de algún tipo de tratamiento antes de su envío al solicitante.
Para ello vamos a entrar de nuevo a las propiedades de la aplicación Web en la que estamos trabajando mediante el administrador del IIS y vamos a forzar que cualquier tipo de fichero pase al motor .NET.
Difiere un poco de la versión 5 a la 6 del IIS.
En la Versión 5 entramos en las propiedades de nuestra aplicación Web , y en la pestaña de Directorio virtual, a Configuración

Aquí podremos ver las extensiones que por defecto se envían a su procesamiento con .Net (a través de la dll aspnet_isapi.dll) y podremos añadir las extensiones que necesitemos para nuestro objetivo. En la versión 5 añadiremos directamente la extensión objetivo, el path a la dll, y los comandos o acciones que provocarán este envío (en principio, get, post, put y head).
Podemos emplear el carácter comodín * para hacer referencia todos los tipos de ficheros solicitados y no tener que mapear cada una de las extensiones.

En la versión 6 del IIS, la operativa es la misma; cambia un poco la interfaz y la configuración de las las asignaciones de recursos a la dll correspondiente para el caso de determinar todos los ficheros, que ya no se hace en la ventana anterior, sino que tiene un interfaz propio y separado del resto de extensiones directas.


· Modificando el Web.config
Si recordáis el punto anterior del uso de filtros para generar el Rewrite, había un fichero Ini donde almacenábamos las expresiones regulares que haríamos servir para nuestro fin.
En el caso que nos ocupa, estas expresiones regulares las almacenaremos en un repositorio, un fichero de texto, y por la organización que necesita el mismo, regla-reescritura, el formato más adecuado, es un xml.
Llegados a este punto, podemos optar por dos opciones, usar nuestro web.config, o crear un fichero xml específico para esta función. En mi opinión es más eficiente, hacer uso del web.config, pues tendremos nuestras reglas en una sección, dentro de la organización jerárquica que nos proporciona, posibilidad de asociarle un manejador, seguridad integrada que el servidor atribuye ya de por sí a este tipo de ficheros ante intentos de intrusión y obtención del mismo., cosa que tendríamos que implementar nosotros en el caso de usar un fichero independiente. Además nos proporciona una manera eficaz de organizar distintas aplicaciones con temas en común debido a la organización jerárquica de los ficheros de configuración en .NET (machine.configàWeb.config de la raíz del servidoràWeb.config de cada SiteàWeb.config de cada aplicación del Site.) Podréis obtener más información de cómo se organizan los ficheros de configuración aquí.

Como sabemos, todos los valores de configuración de ASP.NET se encuentran anidadas de forma jerárquica en el fichero Web.config, dentro de la etiqueta raíz . De esta manera, para cada sección nueva que añadamos se requiere un controlador apropiado. Estos se definirán en la etiqueta .
El primer paso será preparar la creación de la sección donde guardaremos nuestras expresiones regulares. Esta declaración debe estar dentro de las sección <system.web>
<configsections>
<sectiongroup name="system.web">
<section name="urlrewrites" type= "ReWriter, App_Code">
</sectiongroup>
</configsections>

Podemos ver que esta declaración se subdivide en dos partes.
El grupo al que se añade la misma, sectionGroup, porque la configuración de ASP.NET nos permite agrupar secciones para una mejor organización de las mismas.
La sección que crearemos, con el nombre de la misma, y el controlador que se encargará de su procesamiento. La podemos incorporar al grupo que queramos, pero siempre declararla; además la asociaremos un manejador para la misma donde implementaremos la lógica de la reescritura.
Esto sucede porque ASP.NET deja el procesamiento de las secciones del fichero web.config en manos de algún controlador de sección. Cada uno de estos manejadores que declaremos, simplemente consistirá en una clase que implementa el interfaz IConfigurationsectionHandler. Más información sobre este tema la podréis encontrar aquí.
Un apunte más, los nombres de etiqueta son “Case sensitive”, por lo que habrá que prestar atención al uso de las mayúsculas y minúsculas al declararlas.
Ya sólo nos queda crear la sección y empezar a incorporar las reglas de reescritura en función de cómo las necesitemos. Siguiendo el ejemplo, quedaría de la siguiente manera:
<rewriterurl>
<regla>
<url>expresion regular a buscar</url>
<rewrite>pagina a la que redigiremos</rewrite>
</regla>
<regla>
<url>…</url>
<rewrite>…</rewrite>
</regla>
</rewriterurl>

· Capturando las peticiones
Para capturar las peticiones de páginas, disponemos de varias opciones. Explicaré la que más se integra en la arquitectura propuesta por ASP.NET 2.0, integrando un módulo en el directorio App_Code, aunque veremos un repaso rápido por las demás opciones.
· Global.asax. La opción más simple y más rápida de implementar. Sólo necesitaremos una referencia en el global.asax al módulo que hemos creado (ver la sección sobre el web.config) y hacer la llamada a los métodos necesarios dentro de el evento BeginRequest, pasándo como parámetro el “request.path que nos llega en la petición del cliente.
Las ventajas son su simplicidad y rapidez de implemetanción, sin que tengamos que sacar la lógica a un módulo propio externo.
· Una dll externa. Podemos implementar toda la lógica del rewrite en una dll externa al proyecto, incorporándolo al directorio bin de nuestro proyecto, haciendo referencia a la misma. El ensamblado que generemos debe ir firmado y por tanto tener un nombre seguro (strongname) e ir incorporado en el GAC. (más info sobre ensamblados firmados aquí
Las ventajas, todas las referentes a modularizar una aplicación, reutilización de código, claridad del mismo, etc.
· Módulo compilado en el App_Code. La implementación es la misma que en el caso de una dll externa, solo que en este caso el código lo generaremos y compilaremos dentro de la carpeta de sistema App_Code.
Ventajas, aprovechamos la arquitectura que nos proporciona NET con la compilación en tiempo de ejecución, la claridad del código.
Desventajas, para quien no este familiarizado con ello, la pelea que supone pelearnos con la generación y declaración del módulo.
· Proceso general en cualquiera de los tres casos anteriores
Una vez hecho esto, comienza la captura de peticiones.
Capturamos el evento BeginRequest ante la llegada de una petición de recursos a nuestra aplicación.
Pasamos el path del recurso solicitado, MEDIANTE LA PROPIEDAD Request.path actual, a nuestro proceso de reescritura, que se encargará de buscar coincidencias en las reglas que hemos generado en nuestro Web.config. Para ello, en nuestro caso, buscará el path en el nodo “url”.
Este proceso en caso de coincidencia nos devolverá el path de reescritura que se encuentra, en nuestro ejemplo, en la misma regla, en el nodo “rewrite”. En caso de no encontrar ninguna coincidencia, mantendrá el path original que nos ha llegado.
Al finalizar, llama al método RewritePath, con un parámetro que será el path, cambiado o no, que será finalmente el recurso que enviaremos al cliente.

En el próximo artículo daremos un repaso a las expresiones regulares que usaremos para hacer la reescritura así como todos los problemas que me encontré durante el desarrollo y alguna forma de solucionarlos.