Practical .NET

Processing Every Request and Response in ASP.NET

Every once in a while, I have some function that I want performed by several different Action methods. If those Actions are in several different controllers, then the problem is probably best referred to as a "cross-cutting concern." A cross-cutting concern is something that applies in many places in your application but not every place. Typical examples are authentication and logging: You want to lock users out of some Action methods and not others, and you want to log activity on some Controllers and not others.

There are several ways to address this problem -- adding a method to some class and calling that method from the start of each Action method just being the most obvious. The good news here is that all your other options are easier to implement and maintain.

For Ad Hoc Scenarios
One solution is to package the code you want to execute into your own custom Action Filter attribute and apply that attribute to the places where you want. This is the solution that makes the most sense when the Action methods you want to apply this functionality to are truly random (that is, not all the methods in all the controllers) or where you want to be able to remove the functionality easily. For example, if you add logging to a method to track down a problem, you can turn off that logging just by removing the attribute from the method.

To create a custom Action Filter, just create a class that inherits from ActionFilterAttribute and override the OnActionExecuting method and/or the OnActitionExecuted methods. Your OnActionExecuting method will be called for you automatically before your Action method is called. That method is passed a property-rich ActionExecutingContext object that gives you access to all sorts of information about the request.

On the other hand, the OnActionExecuted method is called after your Action method has executed, letting you work with the output of your Action method. The OnActionExecuted method is passsed the ActionExecutedContext object. As an example, the Result property on the ActionExecutedContext object gives you access to the View returned by the Action method.

A skeleton custom Action filter looks like this:

public class GenericActionFilter: ActionFilterAttribute
  public override void OnActionExecuting(ActionExecutingContext filterContext)
    // with the filterContext object before executing the method

  public override void OnActionExecuted(ActionExecutedContext filterContext)
    // with the filterContext object after executing the method

You can add a constructor and properties to your Action filter to allow you to pass values to your attribute when you apply it to an Action method. Within your methods, you can use those values to customize your attribute's behavior.

This code, for example, has a constructor that accepts a parameter called Type and a property called priority:

public class GenericActionFilter: ActionFilterAttribute
  public int Priority { get; set; }
  public GenericActionFilter(string Type)

To use this attribute on an Action method, you would apply it like this:

[GenericActionFilter("ImportantType", Priority = 3)]
public ActionResult Index()

For Whole Controllers
If you want to apply some additional functionality to whole controllers, you can create a class that inherits either from the Controller class (for ASP.NET MVC applications) or the ApiController class (for ASP.NET Web API applications). You can then have your MVC or Web API Controllers inherit from your new base class. This is a better solution when you really do want to apply a change to every controller in your site.

Within your new base class you'll find you have any number of methods that you can override to provide additional functionality to your Controllers. For example, your base class has overridable OnActionExecuting and OnActionExecuted methods that work like the equivalent methods in Action Filter attributes, even to being passed ActionExecutingContext and ActionExecutedContext objects (for other methods in your base class, the Controller's HttpContext, Request and Response properties give you access to information about the current request).

You're also free to override the helper methods built into the base class that you normally call from your Action methods: View, PartialView, File, RedirectToResult and so on. In your version of the method you can modify the request made by the class, call the base method in the System.Web.Mvc.Controller class, and then return the result to the caller, perhaps with some additional modifications.

This technique is so generally useful that I recommend to my clients that they create a base Controller or ApiController class when they set up a new application and have all their application's Controllers inherit from that class, even if they can't currently imagine a use for this class. It's less work to add functionality to every controller if you've got your base class in place.

At the site level, you have a third option: HTTP Modules in ASP.NET MVC and Message Handlers in ASP.NET Web API. They're sufficiently interesting, however, that I'll devote a separate column to them.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at

comments powered by Disqus


  • GitHub Copilot for Azure Gets Preview Glitches

    This reporter, recently accepted to preview GitHub Copilot for Azure, has thus far found the tool to be, well, glitchy.

  • New .NET 9 Templates for Blazor Hybrid, .NET MAUI

    Microsoft's fifth preview of .NET 9 nods at AI development while also introducing new templates for some of the more popular project types, including Blazor Hybrid and .NET MAUI.

  • What's Next for ASP.NET Core and Blazor

    Since its inception as an intriguing experiment in leveraging WebAssembly to enable dynamic web development with C#, Blazor has evolved into a mature, fully featured framework. Integral to the ASP.NET Core ecosystem, Blazor offers developers a unique combination of server-side rendering and rich client-side interactivity.

  • Nearest Centroid Classification for Numeric Data Using C#

    Here's a complete end-to-end demo of what Dr. James McCaffrey of Microsoft Research says is arguably the simplest possible classification technique.

  • .NET MAUI in VS Code Goes GA

    Visual Studio Code's .NET MAUI workload, which evolves the former Xamarin.Forms mobile-centric framework by adding support for creating desktop applications, has reached general availability.

Subscribe on YouTube