Anton's thoughts on consulting, project management and application development.

Update: Sam Saffron has fixed this issue in the latest version of Mvc-Mini-Profiler.

It took days to figure out why Firefox was aborting all requests after my login screen. So, I will make the conclusion of my search bold and underlined:

If you are using Mvc-mini-profiler and only logging to the database, you will eventually come to a time when the number of GUIDs that Mvc-mini-profiler inserts into your HTTP responses (X-MiniProfiler-Id headers) will grow to the point where Firefox will silently drop any requests to your website. Firefox will show GET requests with undefined response codes and refuse to load any further pages from your site until the Mvc-Mini-Profiler is turned off.

The fix for this is to create a custom SqlStorage provider for Mvc-mini-profiler and override the HasUserViewed field. Here is my attempt at this:

public class MvcMiniProfilerStorage : SqlServerStorage
    {
        public MvcMiniProfilerStorage(string connectionString)
               : base(connectionString)
        {
        }

        /// <summary>
        /// 	Stores  to dbo.MiniProfilers under its ; 
        /// 	stores all child Timings and SqlTimings to their respective tables.
        /// </summary>
        public override void Save(MiniProfiler profiler)
        {
            const string sql =
                @"insert into MiniProfilers
            (Id,
             Name,
             Started,
             MachineName,
             [User],
             Level,
             RootTimingId,
             DurationMilliseconds,
             DurationMillisecondsInSql,
             HasSqlTimings,
             HasDuplicateSqlTimings,
             HasTrivialTimings,
             HasAllTrivialTimings,
             TrivialDurationThresholdMilliseconds,
             HasUserViewed)
select       @Id,
             @Name,
             @Started,
             @MachineName,
             @User,
             @Level,
             @RootTimingId,
             @DurationMilliseconds,
             @DurationMillisecondsInSql,
             @HasSqlTimings,
             @HasDuplicateSqlTimings,
             @HasTrivialTimings,
             @HasAllTrivialTimings,
             @TrivialDurationThresholdMilliseconds,
             @HasUserViewed
where not exists (select 1 from MiniProfilers where Id = @Id)";
            // this syntax works on both mssql and sqlite

            using (DbConnection conn = GetOpenConnection())
            {
                int insertCount = conn.Execute(sql,
                    new
                        {
                            profiler.Id,
                            Name = Truncate(profiler.Name, 200),
                            profiler.Started,
                            MachineName = Truncate(profiler.MachineName, 100),
                            User = Truncate(profiler.User, 100),
                            profiler.Level,
                            RootTimingId = profiler.Root.Id,
                            profiler.DurationMilliseconds,
                            profiler.DurationMillisecondsInSql,
                            profiler.HasSqlTimings,
                            profiler.HasDuplicateSqlTimings,
                            profiler.HasTrivialTimings,
                            profiler.HasAllTrivialTimings,
                            profiler.TrivialDurationThresholdMilliseconds,
                            // BUG: Too many X-MiniProfiler-Id headers cause
                            // Firefox to stop all requests
                            //
                            // This hack marks all entries as read so that
                            // they do not end up part of that header.
                            HasUserViewed = true    
                        });

                if (insertCount > 0)
                {
                    SaveTiming(conn, profiler, profiler.Root);
                }
            }
        }

        private static string Truncate(string s, int maxLength)
        {
            return s != null && s.Length >
                        maxLength ? s.Substring(0, maxLength) : s;
        }
    }

Then it’s a simple matter of making sure that the Mvc-mini-profiler uses your version of this class rather than it’s own SqlServerStorage class.

MiniProfiler.Settings.Storage = new MvcMiniProfilerStorage("connStr");

This should take care of your Mvc-Mini-Profiler headaches.

About these ads

Comments on: "Firefox & Mvc-Mini-Profiler Gotcha!" (4)

  1. Nice workaround. Do the profiled requests still show up in the top corner of the page when it loads?

  2. If you leave the includes in your page, you will get at least the one displayed Chiklet for the page you are currently on.

    However, I have removed the need for this altogether by creating a back-end dashboard for this purpose.

    Description: http://antonvishnyak.wordpress.com/2011/09/07/building-an-mvc-mini-profiler-dashboard/

    Source Code on Google Code

  3. I also fixed this in the main branch, max unviewed is hardcoded at 20

  4. Thanks, Sam! I will update the post to let everyone know.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: