tags:

views:

383

answers:

3

Hello, I'd like to add an output to all my ASP.NET MVC pages via the master page which shows the render time of the current page. How could I do this?

+6  A: 

This is tricky, because before you can render the page you have to have all your ViewData added to it.

You can get the total time it took to execute the controller action by writing a custom ActionFilterAttribute and overriding OnActionExecuting to start a timer, and OnActionExecuted to get the elapsed time and store it to ViewData. When the ActionResult is executed, it can take that time and render it into your View.

That may be close enough for your needs? Unfortunately, to get the grand total time of both the Action and the Result being executed, you would need to override OnActionExecuting and OnResultExecuted in your Controller, but at that point it's too late to add information to the View, as it's already been rendered. You could log it to a file however, see this link for an example.


Okay, here's an example timer action filter. Add this as a class into your project, and then you can tag any controller method with [ActionTimer], and it will add the elapsed time into a ViewData bucket called "_ElapsedTime", which you can print out on your views.

using System.Web.Mvc; 
using System.Diagnostics;

namespace MvcApplication1  {
    public class ActionTimerAttribute : ActionFilterAttribute
        {
            public ActionTimerAttribute()
            {
                // Make sure this attribute executes after every other one!
                this.Order = int.MaxValue;
            }

            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                var controller = filterContext.Controller;
                if (controller != null)
                {
                    var timer = new Stopwatch();
                    controller.ViewData["_ActionTimer"] = timer;
                    timer.Start();
                }
                base.OnActionExecuting(filterContext);
            }

            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                var controller = filterContext.Controller;
                if (controller != null)
                {
                    var timer = (Stopwatch)controller.ViewData["_ActionTimer"];
                    if (timer != null)
                    {
                        timer.Stop();
                        controller.ViewData["_ElapsedTime"] = timer.ElapsedMilliseconds;
                    }
                }
            }
        } }

As I mentioned earlier, this won't include the time it took to actually render the ActionResult. If you take a look at the example I linked though, it shows you how you could do this to a log file, and also gives you an idea of how the four action filter events can be used.

womp
Could you give me a small example how to do at least the easier way (overriding ActionFilter and then storing the result in ViewData)?
Alex
Sure... give me about 20 minutes here and I'll be able to get back to you and type one up.
womp
Thank you!
Alex
This is great - one question: why do you keep checking for controller being null? Can the OnActionExecuting event fire without a controller?
Alex
Yep. You can do this: ActionTimerAttribute att = new ActionTimerAttribute(); att.OnActionExecuted(new ActionExecutedContext());. Why someone would do that is beyond me, but it's possible.
womp
A: 

I would suggest using JavaScript.

Have two times one at the start of the load of the page and one at then end of the page and then you can do a difference for the total time.

By doing it from client side script you can get the entire time it take the page to load versus how long the server takes.

dionysus55
this will show you how long it took for the browser (not the server) to render the page
Chris Shouts
Using Javascript in this manner would only be able to tell him the time it took for the browser to render the page between the Javascript calls. This has nothing to do with the time it takes for the server to serve the request.
richardtallent
Depends on your point of view...if you are doing this for the benefit of the user experience, it's completely valid. You are doing it for the purpose of server performance tuning it's not. But the OP is unclear on the purpose.
Webjedi
No where in the question does it state that the user only cares about server time.
dionysus55
@dionysus: Yes, I meant server time. Thank you though!@webjedi: Yes this is just to have a simple way to keep track of performance.
Alex
A: 

You could measure the time, and save it in the session after you rendered the view, then make an Ajax call to retrieve the time.

Runeborg