Friday, June 21, 2013

Getting MiniProfiler to work with WebAPI and EF5 Code First

I have, in my head, a set of technologies that are candidates to add to my regular toolset. One of those tools is MiniProfiler.  MiniProfiler has been around for awhile and, truth to be told, I did spend some time trying to get it to work a little over a year ago. Long enough ago such that I no longer remember why I couldn’t get it to work, but short enough that I do remember having problems with it. Since then I’ve switched jobs and have been working on a project where introducing MiniProfiler wasn’t really possible so I put the tool back on the shelf. Partly because it’s always bugged me that I never got it working for me and partly because it looks like it might now come in handy on a project, I decided to get back on the horse, as it were and get it figured out.

Let me first say that the online documentation is excellent and comprehensive, it does look a bit out of date. Currently the instructions are for Entity Framework 4.1 and 4.2.  As of this writing I’m using EF5 and CTPs of EF6 are available.  Fortunately, the instructions – minus the caveats for 4.2 – work pretty well.  In fact, all of the information you need to use MiniProfiler with WebAPI and EF5 Code First is contained in the documentation, but not always where you would expect.

Also, if you’re like me, you’ve gotten used to just installing NuGet packages and using them without a lot of extra configuration. That’s not the case here. It’s important to read all of the instructions for installing and configuring the MiniProfiler for use. There’s a fair amount of hand-crafted set up that you will need to make it work, not all of it listed in the Getting Started section of the documentation.

Start by adding the MiniProfilerEF NuGet package to your solution. I used version 2.1 (published on 3/4/2013). It has a dependency on the MiniProfiler package (also version 2.1, published on the same date) so you will get both when installing the Entity Framework integration.

Next up, you’ll need a web page.  Fortunately, my WebAPI project came with an MVC home controller equipped with an Index action and associated view. For my exploration I made use of this set up. In Views\Shared\_Layout.cshtml I added the following (I’ve included a bit of context). Note that I inserted the MiniProfiler scripts after jQuery and before any page-specific scripts are included.  MiniProfiler requires jQuery 1.7+ and will attempt to load it if it isn’t installed.


<html>
    @using StackExchange.Profiling  
    <head>
         ...
    <head>
    <body>
        ... content ...
  
        @RenderBody()

        @Scripts.Render("~/bundles/jquery")

        @MiniProfiler.RenderIncludes()  

        @RenderSection("scripts", required: false)
    </body>
</html>

In addition to this, I had to make a change to my web.config file, adding the handler for the MiniProfiler resources (that is the CSS and JavaScript files used to render the results, located at /mini-profiler-resources/… ).  I added the following to the default web.config in the /system.webServer/handlers section.  This bit is listed in the troubleshooting section of the documentation and it was required even though my web.config did not have runAllManagedModulesForAllRequests=false. Extension-less handling for MVC is enabled in my configuration via handlers, not by setting the value of that parameter to true and thus I needed to add the MiniProfiler handler manually.

<add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" >

Now that the MVC application is set up to display the MiniProfiler results, it’s time to enable it in the application. For Entity Framework, this is the easy part. Simply add the initialization to the Application_Start method in Global.asax.cs, then initiate the collection of profiling data in Application_BeginRequest and stop the profiler in Application_EndRequest. I’ll note that I found I did not have to specify the SqlServerFormatter explicitly to get SQL commands that were readable and usable with SQL Server Management Studio (when no formatter is supplied, the raw SQL command is used). That may not be the case for all providers or different versions of Entity Framework. If so, simply uncomment the line setting the formatter.

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...
        
        //MiniProfiler.Settings.SqlFormatter = new StackExchange.Profiling.SqlFormatters.SqlServerFormatter();
        MiniProfilerEF.Initialize();
    }

    protected void Application_BeginRequest()
    {
        if (Request.IsLocal)
        {
            MiniProfiler.Start();
        }
    }

    protected void Application_EndRequest()
    {
        MiniProfiler.Stop();
    }
}

Note also, that the pre-condition for running the profiler is that the request be a local request. If you plan on running this in a performance test environment, you’ll need to modify the condition for starting the profiler. I will probably drive it with values from the web.config file (AppSettings). See the documentation for more configuration options and usage for more complex examples.

The final step is to write the code to query your API from /home/ and observe the results. I picked a simple WebAPI example – and implemented part of it. Once I had enough that I could query my API, I executed the project in the debugger and my profiler results showed up on the page in the upper left corner.