15

I am using an ActionFilter to log all action calls of my ASP.NET Web API project. The OnActionExecuted method tells a lot about what's been happening.

I just can't figure out how to find an efficient way to measure execution time...

2
  • 1
    System.Diagnostics.Stopwatch?
    – Joe
    Commented Jun 12, 2013 at 15:18
  • Also check this article for both MVC APIs and Web APIs. Commented Jun 29, 2015 at 14:41

2 Answers 2

36

Something like this should do the trick...

public class StopwatchAttribute : ActionFilterAttribute
{
    private const string StopwatchKey = "StopwatchFilter.Value";

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        base.OnActionExecuting(actionContext);

        actionContext.Request.Properties[StopwatchKey] = Stopwatch.StartNew();
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);

        Stopwatch stopwatch = (Stopwatch)actionExecutedContext.Request.Properties[StopwatchKey];
        // TODO something useful with stopwatch.Elapsed
        Trace.WriteLine("Elapsed = " + stopwatch.Elapsed);
    }
}

Here we store a new Stopwatch in the request properties and stop it when the request has completed.

8
  • Why do u save the instance in the request ? Why don't u make it a private field ?
    – user49126
    Commented Sep 23, 2014 at 17:35
  • 5
    @user49126 Action filters are shared across multiple actions and there could be multiple in-flight requests. To eliminate concurrency concerns it is safest to store the instance on the request.
    – Dean Ward
    Commented Sep 24, 2014 at 10:59
  • 1
    Also there is an improved solution stays here link
    – zapoo
    Commented Aug 5, 2015 at 12:06
  • Does this work for async methods? i.e. If using async then will this time the duration of the call including all continuations until the bytes are written to the response stream? Commented Oct 23, 2015 at 15:02
  • @LukePuplett Stopwatch works by taking a snapshot of the system ticks when started and computing the difference from that snapshot when queried. In this case though we're using an action filter so it only includes the time that it takes to execute the action itself. If you need to get timing information for the full request you should look into the Tracing API instead.
    – Dean Ward
    Commented Oct 24, 2015 at 19:02
0

You will need these using statements to run the above example:

using System.Diagnostics;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

I registered the filter globally for my whole api in WebApiConfig class like this: config.Filters.Add(new StopwatchAttribute());

and in case you want to print out the name of the controller with the elapsed time, here is how you can get the name of the controller in the OnActionExectued method:

string ControllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName;

Not the answer you're looking for? Browse other questions tagged or ask your own question.