MiniProfiler with ASP.Net MVC

At work we were having trouble with the amount of time one of our pages was taking to move forward. To be fair, this page was doing a lot of work and posting a lot of data in one shot, but it really shouldn't have been taking upwards of 15-20 seconds.

Using the normal means (Fiddler, Glimpse, Chrome tools, etc), we were still having trouble pinpointing the problem. We ruled out the jQuery validator, JSON serializing and the action method in our controller.

So along came MiniProfiler to the rescue.

To start, use Nuget to install MiniProfiler into the project. From the Project Management Console, type:

Install-Package MiniProfiler.MVC3  

A new file called MiniProfiler.cs will be added to the App_Start folder. Looking in the Init() method in the MiniProfilerStartupModule class, code has already been added to limit MiniProfiler to run for local requests only. We wanted to take this one extra step and add configuration to shut it completely off when the application goes into the wild, but give us the ability to turn it on at a client site, just in case.

In the web.config file, we added:

<appSettings>  
     ...
     <add key="ga:profiler" value="true" />
</appSettings>  

In the MiniProfiler.cs file, we built a new method to access this configuration setting:

private static bool ProfilerConfiguredToRun()  
{
    return System.Configuration.ConfigurationManager.AppSettings["ga:profiler"] == "false";
}

We updated the Init() method to look like:

public void Init(HttpApplication context)  
{
    context.BeginRequest += (sender, e) =>
    {
        var request = ((HttpApplication)sender).Request;
        if (request.IsLocal && ProfilerConfiguredToRun()) 
            MiniProfiler.Start(); 
    };

    context.EndRequest += (sender, e) =>
    {
        MiniProfiler.Stop();
    };
}

To place a wrapper around every request, you could add something like:

protected void Application_BeginRequest(object sender, EventArgs e)  
{
    var profiler = MiniProfiler.Current;

    using (profiler.Step("Begin Request")) { }
}

protected void Application_EndRequest(object sender, EventArgs e)  
{
    var profiler = MiniProfiler.Current;

    using (profiler.Step("End Request")) { }
}

To profile a method, perhaps a controller action,

public ActionResult SomeAction(ViewModel viewmodel)  
{
    var profiler = MiniProfiler.Current;
    using (profiler.Step("Step 1: Saving"))
    {
        using (profiler.Step("Step 1: Saving"))
        {
            var application = _service.Load(viewmodel.Id);
        }

        var path = Url.Action("Finish", "Appl", new { area = "Cust" });
        return Json(new { success = true, appl = application, pathNext = myPath });
    }
}

When your application runs, you should now see your profiler results in the upper left corner of your browser window.

During this little adventure, one more problem cropped up regarding the sheer size of the data that we were trying to send through the profiler. It was actually maxing out what was allowed over the pipe.

To temporarily get around this, add the following to Application_Start() in the global.asax.cs file (comment or remove this when you are done with it):

MiniProfiler.Settings.MaxJsonResponseSize = int.MaxValue;  

Hopefully this provides a good starting point for the next person that may need to jump in and use MiniProfiler.

Here be monsters...

Alrighty...my good buddy Ben, over at benmacleod.com started blogging and has basically shamed me into doing the same.

A little about me. I am a .Net developer with an insurance software company in sunny Halifax, Nova Scotia. I'm going to try and use this site as a way to document things as I learn them, or as I write new things.

For the most part, coding will be the focus, but I can't promise that guitars (oh yeah), movies and other things I think are cool won't creep in.

Opening posts are the hardest thing in the world to write...

<google-bait>George Clooney</google-bait>