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.

Jesse
fuente
7
Vea mi artículo de filtrado msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx
RickAndMSFT

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.

Yngve B-Nilsen
fuente
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>
M. Mennan Kara
fuente
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.

usuario2173353
fuente
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.

Ogglas
fuente