Click here to Skip to main content
15,885,546 members
Articles / Web Development / ASP.NET

Performance Tip: Measure performance of ASP.NET MVC Action Filters

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
26 Sep 2013CPOL3 min read 14K   6   1
Measure performance of ASP.NET MVC Action Filters.

Action Filtering is one of the “hidden parts” of ASP.NET MVC. When checking page execution time, it’s common to measure controller action or view generation, but it’s often uncommon to monitor filters (as for routing). After a few performance reviews, I now think it’s really important to not forget this part.

Just to remember, MVC filters are custom attributes that you put onto action methods/controllers/globally to add common functionality, with pre- and post-processing behaviors.

How does the filter work? A good starting point is ASP.NET MVC source code and especially ControllerActionInvoker.

Using Miniprofiler

We all love great debugging tools and ASP.NET MVC MiniProfiler is one of them. However it does not come with a native way to instrument filter execution. But that’s however the tool we will use to report execution timings.

In order to evaluate performance of filters, a typical ASP.NET developer could create a new base filter attribute, and use this attribute for every filter in the target solution.

A basic implementation could be :

public void OnActionExecuted(ActionExecutedContext filterContext)
{
     using (MiniProfiler.StepStatic("Filter: " + actionFilter.GetType().Name + ".OnActionExecuted", ProfileLevel.Info))
     {
          actionFilter.OnActionExecuted(filterContext);
     }
}

Even if it’s a valid OOP approach, I don’t like to change the default base class for all of the custom filters. Obviously, this will not work for third party filters coming from my favorites Nuget packages. The problem is not in this implementation but how we plug it into ASP.NET MVC. However, I keep the code for the future.

An experienced ASP.NET MVC developer knows it is relatively easy to customize the default ControllerActionInvoker. As suggested in this post . The next step is to create an ActionInvoker that will wrap all ActionFilterAttributes with our wrapper class.

Especially, we will override the GetFilters method as follows:

protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
     FilterInfo baseFilters = base.GetFilters(controllerContext, actionDescriptor);

     WrapFilters(baseFilters.ActionFilters);
     WrapFilters(baseFilters.ResultFilters);

     return baseFilters;
}

Prior to ASP.NET MVC 4, the only way to switch out the action invoker was to write a custom controller factory. That’s not so complicated but it’s so long and annoying…

Since ASP.NET MVC 4, you can now simply inject an IActionInvoker using the dependency resolver. To understand how IoC/DI works in ASP.NET MVC, you could read the ASP.NET tutorial here. http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-dependency-injection

Using Ninject.MVC Nuget package, the final code is:

/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
     kernel.Bind<IActionInvoker>().To<ProfiledActionInvoker>();
}

That’s all, we did it! Here is the result for the standard MVC 4 template and two custom global filters.

profiledglobalfilter

The complete Gist is available here.

OK, I found a problem, how to solve it ?

The code in the filter is generally easy to understand and you should use standard tools (Visual Studio Profiler). However there are two things you’ve got to be carefully taught:

  • Filters instances

Using Filter Attributes, there is only a single attribute instance per application. Use an appropriate store for your filter state (see this post from Brad Wilson).

Using FilterProviders, the filter provider will have a chance to decide whether a particular filter applies to the current request. If so, a new instance of the filter will be created each time.

  • Canceling Filter Execution

According to MSDN, You can cancel filter execution in the OnActionExecuting and OnResultExecuting methods by setting the Result property to a non-null value. I’ve seen many cases where useless filters are invoked; remember everything has a cost.

What about Glimps ?

In Glimpse, the Execution tab shows the ASP.NET MVC execution pipeline of actions, action results, and action filters (including child actions) required to respond to the HTTP request. However, I find the execution tab not clear (too much data) and I’m also less confident in Glimpse for production.

Because you have nothing to do, it’s not so funny :-)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Betclic
France France
I am Head of Software Development at Betclic France. I manage the Paris Dev Team, consisting of 35+ talented people, in various technical and functional projects in the fields of sports betting, poker, casino or horse betting.

Check out our technical blog at https://techblog.betclicgroup.com
This is a Organisation

3 members

Comments and Discussions

 
GeneralMy vote of 4 Pin
Robert Hoffmann26-Sep-13 5:12
Robert Hoffmann26-Sep-13 5:12 
Thanks for reminding me to relook into glimpse Smile | :) Also love how metrics oriented your group seems to be as far as resolving errors go, wish our company was a bit stricter in that regard !

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.