2009-01-08 20 views
5

Estoy construyendo un CMS bastante simple. Necesito interceptar solicitudes para la mayoría de las páginas .aspx en mi aplicación web, a fin de obtener control completo sobre la salida. En la mayoría de los casos, la salida se extraerá de la memoria caché y será simplemente HTML sin formato.Custom PageHandlerFactory for .aspx

Sin embargo, todavía hay un par de páginas que necesitaré usar asp: controles en. Supongo que la mejor manera de evitar algunas solicitudes particulares sería heredar System.Web.UI.PageHandlerFactory y simplemente llamar a la implementación de MyBase cuando lo necesite (corríjanme si me equivoco aquí). ¿Pero cómo transfiero todas las demás solicitudes a mi controlador personalizado?

Respuesta

3

Cuando escribí un CMS simple, tuve dificultades para usar el PageHandlerFactory para que hiciera lo que yo quería. Al final, cambié a un IHttpModule.

Mi módulo primero verificaba si había un archivo .aspx en la ruta solicitada. Solo lo haría si la página tiene controles de usuario o no cabía en el CMS por algún motivo. Entonces, si el archivo existiera, volvería a salir del módulo. Después de eso, miraría la ruta solicitada y la condensaría en una "etiqueta de navegación". Así ~/aboutus/default.aspx se convertiría en page.aspx? Nt = aboutusdefault. page.aspx cargaría el contenido adecuado desde el CMS. Por supuesto, la redirección se produce en el lado del servidor, por lo que los usuarios/arañas nunca saben que sucedió algo diferente.

using System; 
using System.Data; 
using System.Collections.Generic; 
using System.Configuration; 
using System.Reflection; 
using System.Text.RegularExpressions; 
using System.Web; 

namespace MyCMS.Handlers { 
    /// <summary> 
    /// Checks to see if we should display a virutal page to replace the current request. 
    /// Code adapted from: 
    /// Rewrite.NET -- A URL Rewriting Engine for .NET 
    /// By Robert Chartier 
    /// http://www.15seconds.com/issue/030522.htm 
    /// </summary> 
    public class VirtualPageModule : IHttpModule { 
     /// <summary> 
     /// Init is required from the IHttpModule interface 
     /// </summary> 
     /// <param name="Appl"></param> 
     public void Init(System.Web.HttpApplication Appl) { 
      // make sure to wire up to BeginRequest 
      Appl.BeginRequest += new System.EventHandler(Rewrite_BeginRequest); 
     } 

     /// <summary> 
     /// Dispose is required from the IHttpModule interface 
     /// </summary> 
     public void Dispose() { 
      // make sure you clean up after yourself 
     } 

     /// <summary> 
     /// To handle the starting of the incoming request 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="args"></param> 
     public void Rewrite_BeginRequest(object sender, System.EventArgs args) { 
      // Cast the sender to an HttpApplication object 
      HttpApplication httpApp = (HttpApplication)sender; 

      // See if the requested file already exists 
      if (System.IO.File.Exists(httpApp.Request.PhysicalPath)) { 
       // Do nothing, process the request as usual 
       return; 
      } 

      string requestPath = VirtualPathUtility.ToAppRelative(httpApp.Request.Path); 

      // Organic navigation tag (~/aboutus/default.aspx = nt "aboutusdefault") 
      Regex regex = new Regex("[~/\\[email protected]#$%^&*()+=-]"); 
      requestPath = regex.Replace(requestPath, string.Empty).Replace(".aspx", string.Empty); 
      string pageName = "~/page.aspx"; 
      string destinationUrl = VirtualPathUtility.ToAbsolute(pageName) + "?nt=" + requestPath; 
      SendToNewUrl(destinationUrl, httpApp); 
     } 

     public void SendToNewUrl(string url, HttpApplication httpApp) { 
      applyTrailingSlashHack(httpApp); 
      httpApp.Context.RewritePath(
       url, 
       false // RebaseClientPath must be false for ~/ to continue working in subdirectories. 
      ); 
     } 

     /// <summary> 
     /// Applies the trailing slash hack. To circumvent an ASP.NET bug related to dynamically 
     /// generated virtual directories ending in a trailing slash (/). 
     /// As described by BuddyDvd: 
     /// http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105061 
     /// </summary> 
     /// <param name="httpApp">The HttpApplication.</param> 
     /// <remarks> 
     /// Execute this function before calling RewritePath. 
     /// </remarks> 
     private void applyTrailingSlashHack(HttpApplication httpApp) { 
      if (httpApp.Request.Url.AbsoluteUri.EndsWith("/") && !httpApp.Request.Url.AbsolutePath.Equals("/")) { 
       Type requestType = httpApp.Context.Request.GetType(); 
       object clientFilePath = requestType.InvokeMember("ClientFilePath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty, null, httpApp.Context.Request, null); 
       string virtualPathString = (string)clientFilePath.GetType().InvokeMember("_virtualPath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, null, clientFilePath, null); 
       clientFilePath.GetType().InvokeMember("_virtualPath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, clientFilePath, new object[] { virtualPathString }); 
       requestType.InvokeMember("_clientFilePath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, HttpContext.Current.Request, new object[] { clientFilePath }); 
       object clientBaseDir = requestType.InvokeMember("ClientBaseDir", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty, null, httpApp.Context.Request, null); 
       clientBaseDir.GetType().InvokeMember("_virtualPath", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, clientBaseDir, new object[] { virtualPathString }); 
       requestType.InvokeMember("_clientBaseDir", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField, null, HttpContext.Current.Request, new object[] { clientBaseDir }); 
      } 
     } 
    } 
} 
+0

Ya veo. Este enfoque parece factible y bastante bueno para mí. ¡Gracias! Aún así intentaré que la fábrica funcione. Tal vez pueda usar RewritePath en la fábrica para apuntar a mi controlador (y luego devolver nulo) ...? –

0

¿Quiere decir que va a inyectar controles? Si ese es el caso, es posible que desee considerar una clase base requerida en lugar de la clase Page. Page implementa IHttpHandler, por lo que puede crear una clase derivada y luego cambiar sus páginas para derivar de su clase derivada. Tendrás mucho más control sobre tu página y podrás conectarla y renderizarla.

+0

No creo que sigas. –