Pregunta

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

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

¿Fue útil?

Solución

Cuando escribí un CMS simple, tuve dificultades para usar la página PageHandlerFactory para que hiciera lo que quería. Al final me cambié a un IHttpModule.

Mi módulo primero verificará si había un archivo .aspx en la ruta solicitada. Solo lo haría si la página tiene controles de usuario o si no encaja en el CMS por alguna razón. Entonces, si el archivo existiera, volvería a salir del módulo. Después de eso, vería la ruta solicitada y la condensaría en una " etiqueta de navegación. & Quot; Así, ~ / aboutus / default.aspx se convertiría en page.aspx? Nt = aboutusdefault. page.aspx cargaría el contenido adecuado del CMS. Por supuesto, la redirección se produce en el lado del servidor para que los usuarios / arañas nunca sepan 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("[~/\\!@#$%^&*()+=-]");
            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 });
            }
        }
    }
}

Otros consejos

¿Quieres decir que vas 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á mucho más control sobre su página y podrá conectarse a ella y a su representación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top