ASP.NET MVC 4 intercept all incoming requests
Asked Answered
B

4

82

Is there a way for me to catch all incoming requests to my ASP.NET MVC 4 app and run some code before continuing the request onward to the specified controller/action?

I need to run some custom auth code with existing services, and to do this properly, I'll need to be able intercept all incoming requests from all clients to double check some things with the other service.

Butterfat answered 30/7, 2012 at 17:51 Comment(1)
See my filtering article msdn.microsoft.com/en-us/library/gg416513(VS.98).aspxPleopod
S
83

The most correct way would be to create a class that inherits ActionFilterAttribute and override OnActionExecuting method. This can then be registered in the GlobalFilters in Global.asax.cs

Of course, this will only intercept requests that actually have a route.

Squib answered 30/7, 2012 at 17:54 Comment(9)
The only (ugly) otherway is the protected void Application_BeginRequest(object sender, EventArgs e).Seaquake
Well, I guess you could also create a HttpHandler and register that to catch all in web.config, but that's really dirty :)Squib
Great, thanks! Will mark as answer when enough time has passed.Butterfat
Is there a way to force a redirect from within the OnActionExecuting override?Butterfat
Yeah, you can set the filterContext.Result to a RedirectResultSquib
You can change the result to whatever type of ActionResult you see fitSquib
One thing (I think) to note is that this means you only get requests that match an actual route to an action. If you want to log all requests, I think Application_BeginRequest might be a better option, no?Intarsia
@YngveB-Nilsen could you elaborate on how to override it? I'm stuck at this since I new to VB.Net. Since it is the accepted answer, it could use some more details :)Osteotomy
@Osteotomy Since this answer is from 2012, I'm pretty sure my answer is no longer the complete solution. Take a look at this article: msdn.microsoft.com/en-us/library/dd410056(v=vs.98).aspxSquib
T
39

You can use a HttpModule to accomplish this. Here is a sample I use to calculate the process time for all requests:

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 */ }
    }

}

And this is how you register the module in Web.Config:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="PerformanceMonitorModule" type="Sample.HttpModules.PerformanceMonitorModule" />
    </modules>
<//system.webServer>
Tonguelash answered 30/7, 2012 at 17:57 Comment(3)
If the goal is to capture MVC app requests before they go to the controller, filtering is a much better approach. See my article msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx - my sample has a nice timing filterPleopod
I would recommend against this approach since it uses runAllManagedModulesForAllRequests which is a performance drag. Application_BeginRequest seems like a much simpler way to achieve the resultFanchie
No need for runAllManagedModulesForAllRequests="true" to drag performance down, if all you want is to execute the module for managed code: just specify preCondition="managedHandler" on the module. See: Achtung! IIS7 Preconditions.Volost
S
26

I think that what you search for is this:

Application_BeginRequest()

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

You put it in Global.asax.cs.

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

I use this for debugging purposes but I am not sure how good solution it is for your case.

Septuagenarian answered 10/12, 2013 at 8:44 Comment(0)
G
2

I'm not sure about MVC4 but I think it is fairly similar to MVC5. If you have created a new web project -> look in Global.asax and you should see the following line FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); in the method Application_Start().

RegisterGlobalFilters is a method in the file FilterConfig.cs located in the folder App_Start.

As @YngveB-Nilsen said ActionFilterAttribute is the way to go in my opinion. Add a new class that derives from System.Web.Mvc.ActionFilterAttribute. This is important because System.Web.Http.Filters.ActionFilterAttribute will fail with the following exception for example.

The given filter instance must implement one or more of the following filter interfaces: System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter, System.Web.Mvc.Filters.IAuthenticationFilter.

Example that writes the request to the debug window:

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

In FilterConfig -> RegisterGlobalFilters -> add the following line: filters.Add(new DebugActionFilter());.

You can now catch all incoming requests and modify them.

Gravely answered 25/1, 2018 at 13:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.