ASP.NET MVC 4 intercepta todas las solicitudes entrantes


78

¿Hay alguna forma de capturar todas las solicitudes entrantes a mi aplicación ASP.NET MVC 4 y ejecutar algún código antes de continuar con la solicitud hacia el controlador / acción especificado?

Necesito ejecutar un código de autenticación personalizado con los servicios existentes, y para hacerlo correctamente, tendré que poder interceptar todas las solicitudes entrantes de todos los clientes para verificar algunas cosas con el otro servicio.


Respuestas:


80

La forma más correcta sería crear una clase que herede ActionFilterAttribute y anule el OnActionExecutingmétodo. Esto puede ser registrada en el GlobalFiltersenGlobal.asax.cs

Por supuesto, esto solo interceptará solicitudes que realmente tengan una ruta.


10
La única (fea) otra forma es la protected void Application_BeginRequest(object sender, EventArgs e).
Erik Philips

1
Bueno, supongo que también podrías crear un HttpHandler y registrarlo para capturarlo todo en web.config, pero eso es muy sucio :)
Yngve B-Nilsen

1
¿Hay alguna forma de forzar una redirección desde dentro de la OnActionExecutinganulación?
Jesse

2
Sí, puede configurar el filterContext.Result a RedirectResult
Yngve B-Nilsen

1
Puede cambiar el resultado a cualquier tipo de ActionResult que crea conveniente
Yngve B-Nilsen

38

Puede usar un HttpModule para lograr esto. Aquí hay una muestra que utilizo para calcular el tiempo de proceso para todas las solicitudes:

using System;
using System.Diagnostics;
using System.Web;

namespace Sample.HttpModules
{
    public class PerformanceMonitorModule : IHttpModule
    {

        public void Init(HttpApplication httpApp)
        {
            httpApp.BeginRequest += OnBeginRequest;
            httpApp.EndRequest += OnEndRequest;
            httpApp.PreSendRequestHeaders += OnHeaderSent;
        }

        public void OnHeaderSent(object sender, EventArgs e)
        {
            var httpApp = (HttpApplication)sender;
            httpApp.Context.Items["HeadersSent"] = true;
        }

        // Record the time of the begin request event.
        public void OnBeginRequest(Object sender, EventArgs e)
        {
            var httpApp = (HttpApplication)sender;
            if (httpApp.Request.Path.StartsWith("/media/")) return;
            var timer = new Stopwatch();
            httpApp.Context.Items["Timer"] = timer;
            httpApp.Context.Items["HeadersSent"] = false;
            timer.Start();
        }

        public void OnEndRequest(Object sender, EventArgs e)
        {
            var httpApp = (HttpApplication)sender;
            if (httpApp.Request.Path.StartsWith("/media/")) return;
            var timer = (Stopwatch)httpApp.Context.Items["Timer"];

            if (timer != null)
            {
                timer.Stop();
                if (!(bool)httpApp.Context.Items["HeadersSent"])
                {
                    httpApp.Context.Response.AppendHeader("ProcessTime",
                                                          ((double)timer.ElapsedTicks / Stopwatch.Frequency) * 1000 +
                                                          " ms.");
                }
            }

            httpApp.Context.Items.Remove("Timer");
            httpApp.Context.Items.Remove("HeadersSent");

        }

        public void Dispose() { /* Not needed */ }
    }

}

Y así es como registras el módulo en Web.Config:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="PerformanceMonitorModule" type="Sample.HttpModules.PerformanceMonitorModule" />
    </modules>
<//system.webServer>

3
Si el objetivo es capturar las solicitudes de la aplicación MVC antes de que vayan al controlador, el filtrado es un enfoque mucho mejor. Vea mi artículo msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx - mi muestra tiene un buen filtro de tiempo
RickAndMSFT

1
No recomendaría este enfoque, ya que utiliza runAllManagedModulesForAllRequestsun freno de rendimiento. Application_BeginRequestparece una forma mucho más sencilla de lograr el resultado
Quango

25

Creo que lo que buscas es esto:

Application_BeginRequest()

http://www.dotnetcurry.com/showarticle.aspx?ID=126

Lo pones Global.asax.cs.

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpContext.Current.Request.....;
    }

Utilizo esto con fines de depuración, pero no estoy seguro de qué tan buena solución es para su caso.


2

No estoy seguro de MVC4, pero creo que es bastante similar a MVC5. Si ha creado un nuevo proyecto web -> busque Global.asaxy verá la siguiente línea FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);en el método Application_Start().

RegisterGlobalFilterses un método en el archivo FilterConfig.csubicado en la carpeta App_Start.

Como dijo @ YngveB-Nilsen, ActionFilterAttributeen mi opinión, es el camino a seguir. Agregue una nueva clase que se derive de System.Web.Mvc.ActionFilterAttribute. Esto es importante porque System.Web.Http.Filters.ActionFilterAttributefallará con la siguiente excepción, por ejemplo.

La instancia de filtro dada debe implementar una o más de las siguientes interfaces de filtro: System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter, System.Web .Mvc.Filters.IAuthenticationFilter.

Ejemplo que escribe la solicitud en la ventana de depuración:

public class DebugActionFilter : System.Web.Mvc.ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext actionContext)
  {
    Debug.WriteLine(actionContext.RequestContext.HttpContext.Request);
  }
}

En FilterConfig-> RegisterGlobalFilters-> añadir la siguiente línea: filters.Add(new DebugActionFilter());.

Ahora puede capturar todas las solicitudes entrantes y modificarlas.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.