En el post de Scott Guthrie se recomienda el uso de modulos ya desarrollados, como el url-rewrite, pero mi experiencia es que estos modulos crean muchos problemas con referencias a estilos, imagenes, scripts.
Estos problemas se agravan cuando se usan webforms ASP.NET como adelanta la sección URL Rewriting for ASP.NET Web Forms en las páginas del modulo url-rewite para iis7.
Mi opinión es que el modulo url-rewrite es útil y lo recomiendocuando tienes que trabajar con código ajeno, pero si estas trabajando con un desarrollo propio y tu código está minimamente estructurado será mas eficiente implantar la reescritura de urls en tu codigo. Eficiente tanto en tiempo de ejecución como de desarrollo.
Recordemos que el problema es usar URL del tipo:
http://www.spaintiles.info/dirbeta/0-0-1-1-1-1-15-1-1-E-1/default.aspx
Cuando sabemos que a nuestras páginas les gusta mas del tipo:
http://www.spaintiles.info/dirbeta/default.aspx?P=0-0-1-1-1-1-15-1-1-E-1
El primer paso que equivale la regla de entrada (inbound rule) del Rewrite-module es transformar la URL primera en la segunda.
Para ello usamos el evento de aplicación beginRequest y el metodo rewritePath del contexto. Dicho en simple, en global.asax editamos el procedimiento Application_BeginRequest con un código similar al que sigue.
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) ' Se desencadena al comienzo de cada solicitud Dim pathOriginal = Request.Url.ToString Dim rg As New System.Text.RegularExpressions.Regex("(?Este código podría ser mas simple como el ejemplo dehttp\://\w*(\.\w*)*(?:\:\d*)?)(? /\w*/)(?:(? \w-\w(?:-\w*)*))/(? default\.aspx)(? .*)", RegexOptions.IgnoreCase) Dim captura = rg.Matches(pathOriginal) If captura.Count = 1 Then With captura(0) Dim pagina = .Groups("app").Value + "/default.aspx" If .Groups("queryString").Value.Length = 0 Then pagina += "?P=" Else pagina += .Groups("queryString").Value + "&P=" End If pagina += .Groups("argumentos").Value Context.RewritePath(pagina, False) End With End If End Sub
void Application_BeginRequest(object sender, EventArgs e) { string fullOrigionalpath = Request.Url.ToString(); if (fullOrigionalpath.Contains("/Products/Books.aspx")) { Context.RewritePath("/Products.aspx?Category=Books"); } else if (fullOrigionalpath.Contains("/Products/DVDs.aspx")) { Context.RewritePath("/Products.aspx?Category=DVDs"); } }Pero a mi me gustan las expresiones regulares y tenerlo todo bien identificado.
Importante: En mi código de ejemplo establezco a false el parametro rebaseClientpath: Context.RewritePath(pagina, False) Con esto se resuelven muchos de los problemas relacionados con el uso del simbolo ~ en las urls de imagenes y otros controles web para referenciar la raiz de la aplicación. |
El siguiente paso es reescribir las url para navegación entre páginas. Outbound rule o regla de salida en un rewrite-module.
Aquí es donde puede depender de como estructuraste tu codigo. En mi caso todas las url se generaban en un único procedimiento url(). A efectos de depuración introduje un setting de aplicación que me permite controlar el tipo de url que quiero generar.
Un primer paso es disponer es generar un patrón de url:
If tipoUrl = tiposDeUrl.caminoIzquierdaSimple Then dim privpagina=My.Request.uri.Absoluteuri Dim rg As New Regex( _ "(?El resultado es que en privPagina tendremos algo asi como:http\://\w*(\.\w*)*(?:\:\d*)?/\w*/)" + _ "(?:(? \w-\w(?:-\w*)*)/)?" + _ "(? default\.aspx)(? .*)?", _ RegexOptions.IgnoreCase) Dim capturas = rg.Matches(privpagina) If capturas.Count = 1 Then privpagina = capturas(0).Groups("raiz").Value + _ "{0}/" + _ capturas(0).Groups("pagina").Value End If End If
http://www.spaintiles.info/dirbeta/{0}/default.aspx
Que nos será muy util para reemplazar con el valor del parametro:
Select Case tipoUrl Case tiposDeUrl.parametros resultado = String.Format("{0}?P={1}", pagina, camino) Case tiposDeUrl.caminoIzquierdaSimple resultado = String.Format(pagina, camino) End Select(recordar que por pruedencia tengo un setting para controlar el tipo de url que utilizo)
En este momento podemos probar porque igual todo funciona directamente.
Es posible que surgan problemas:
A) Al hacer click en un botón o similar.
El problema es que hacemos un post del form asp.net y el path está mal escrito.
Solución:
En el evento Load de la página añadid:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load form1.Action = Request.RawUrl .........
B) No se cargan estilos o scripts.
En mi caso opté por cargarlos mediante código:
Public Function RaizApp() As String With me.Request If .ApplicationPath.EndsWith("/") Then Return .ApplicationPath Else Return .ApplicationPath + "/" End If End With End Function Sub CargaJava(ByVal nombre As String) Dim sc As New HtmlGenericControl("script") sc.Attributes("type") = "text/javascript" sc.Attributes("src") = String.Format("{0}Scripts/{1}.js", raizapp, nombre) me.Header.Controls.Add(sc) End Sub Sub CargaCSS(ByVal nombre As String) Dim css As New HtmlLink css.Href = String.Format("{0}estilos/{1}.css", RaizApp, nombre) css.Attributes("type") = "text/css" css.Attributes("rel") = "stylesheet" css.Attributes("media") = "all" me.Header.Controls.Add(css) End Sub Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 'Event load de la página form1.Action = Request.RawUrl If Request.QueryString.AllKeys.Contains("_TSM_HiddenField") Then Exit Sub ToolkitScriptManager1.Scripts.Add(New UI.ScriptReference(RaizApp + "scripts/dfc.js")) CargaJava("jquery-1.3.2.min") CargaCSS("estilocomun") CargaCSS("estiloceramica") CargaCSS("findyourCeramic") ..........Con esto y algun que otro parche ocasional te funcionará la reescritura de URLs.
Puedes encontrar mas información sobre parchear los paths relativos en Fixing Relative Paths in C# ASP.NET When Using Url Rewriting.
Gracias a Walter Wang que me dió la última idea en http://www.eggheadcafe.com/software/aspnet/30412853/url-rewriting-and-file-paths.aspx (otro post interesante sobre el tema.