Using EFProf and MiniProfiler simultaneously in an ASP.NET MVC 5.1, Entity Framework 5 Code-First Project

Posted January 23, 2014 in asp.net-mvc c# efprof entity-framework miniprofiler
Reading time: 2 minutes

We’re already using the excellent Entity Framework Profiler (EFProf) to gauge EF performance in our application. However, we wanted more information about the overall application performance, and thus turned to MiniProfiler.

Installing MiniProfiler was easy enough, but upon running the application, I got an error:

1
Unable to determine the provider name for connection of type 'HibernatingRhinos.Profiler.Appender.ProfiledDataAccess.ProfiledConnection`1[[System.Data.SqlClient.SqlClientFactory, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

Hmm. That’s weird. So I commented out my EFProf initialization code:

1
//EntityFrameworkProfiler.Initialize();

And MiniProfiler worked fine.

I then wrote a test application to try to isolate the problem, and got a different error:

1
System.NotSupportedException: Underlying ProfiledCommand is not cloneable

It turns out that MiniProfiler expects its DbCommand to implement ICloneable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
///
/// clone the command, entity framework expects this behaviour.
///

public ProfiledDbCommand Clone()
{ 
    // EF expects ICloneable
    var tail = _command as ICloneable;
    if (tail == null) 
        throw new NotSupportedException("Underlying " + _command.GetType().Name + " is not cloneable");

    return new ProfiledDbCommand((DbCommand)tail.Clone(), _connection, _profiler);
}

Unfortunately, dotPeek reveals that EFProf’s ProfiledCommand does not implement ICloneable:

1
2
3
4
5
6
7
namespace HibernatingRhinos.Profiler.Appender.ProfiledDataAccess
{
    public class ProfiledCommand : DbCommand
    {
        // ...
    }
}

Fortunately, there is a workaround: initialize MiniProfiler before initializing EFProf. Or, in source code form, do this in Global.asax:

1
2
3
4
5
6
7
8
9
protected void Application_Start()
{
    // ...

    MiniProfiler.Settings.SqlFormatter = new StackExchange.Profiling.SqlFormatters.SqlServerFormatter();
    MiniProfilerEF.Initialize();

    EntityFrameworkProfiler.Initialize();
}

Instead of this:

1
2
3
4
5
6
7
8
9
protected void Application_Start()
{
    // ...

    EntityFrameworkProfiler.Initialize();

    MiniProfiler.Settings.SqlFormatter = new StackExchange.Profiling.SqlFormatters.SqlServerFormatter();
    MiniProfilerEF.Initialize();
}

And EFProf and MiniProfiler will coexist happily together.

(Note that this means EFProf initialization happens in Global.asax instead of in PreApplicationStartMethod installed by the EFProf NuGet package.)

Version information:

  • ASP.NET MVC 5.1.0
  • Entity Framework 5.0.0
  • EFProf Build 2225
  • MiniProfiler 2.1.0


Comments

comments powered by Disqus