Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Mini-Profiler throws LockRecursionException when modifying RouteCollection

I am seeing a pretty crazy error crop up when using the MVC MiniProfiler. Intermittently, the site I'm working on enters a state where every request results in this exception being thrown:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. 
---> System.TypeInitializationException: The type initializer for 'MvcMiniProfiler.MiniProfiler' threw an exception. 
---> System.Threading.LockRecursionException: Write lock may not be acquired with read lock held. 
 This pattern is prone to deadlocks. Please ensure that read locks are released before taking a write lock. 
 If an upgrade is necessary, use an upgrade lock in place of the read lock.
at System.Threading.ReaderWriterLockSlim.TryEnterWriteLockCore(Int32 millisecondsTimeout)
at System.Threading.ReaderWriterLockSlim.TryEnterWriteLock(Int32 millisecondsTimeout)
at System.Web.Routing.RouteCollection.GetWriteLock()
at MvcMiniProfiler.UI.MiniProfilerHandler.RegisterRoutes() 
 in C:\Users\sam\Desktop\mvc-mini-profiler\MvcMiniProfiler\UI\MiniProfilerHandler.cs:line 81
at MvcMiniProfiler.MiniProfiler..cctor() 
 in C:\Users\sam\Desktop\mvc-mini-profiler\MvcMiniProfiler\MiniProfiler.cs:line 241
— End of inner exception stack trace —
at MvcMiniProfiler.MiniProfiler.get_Current()
at TotallyNotOverDrive.Boom.MvcApplication.Application_EndRequest()

The error persists until the app pool is recycled. Looks like somehow a lock is being held which prevents the MiniProfiler from trying to register it's routes. This occurs for requests where I am not starting the MiniProfiler, but during Application_EndRequest I call MiniProfiler.Stop(), which seems to result in a MiniProfiler being created when the Current property is accessed. For a simple solution, I modified EndRequest to use the same logic for stopping the profiler as BeginRequest, so if the request is not using the profiler this error should be avoided completely. I would still like to resolve the actual problem before sending this code to production.

My route table is pretty simple, and is only added to within the Application_Start method. We are not using any other third-party code which might be modifying the route table after startup. The only suspect thing I've done with routing is add a custom Route to the table, but it's a pretty straightforward route, I just needed some more complicated pattern matching than a standard MVC route could accomplish.

I looked through the relevant MiniProfiler code and don't see anything that could be causing a lock to go unreleased, so I'm assuming it's a combination of ASP.NET and MiniProfiler conflicting when accessing the RouteTable. I can't reliably reproduce the problem, so I'm wondering if anyone else has had problems like this with routing. Thanks for any help you can offer.

like image 921
nslowes Avatar asked Apr 06 '12 17:04

nslowes


Video Answer


1 Answers

I think I see what is happening, you need to get the routes registered earlier. You are registering them during EndRequest, at this point there may be other requests in the pipeline which are holding read locks on the route table.

The routes are registered in the static constructor of MiniProfiler. If you access any of the settings in MiniProfiler during Application_Start, this will kick off the static constructor that will register the routes.

For example, try adding something like this, just after registering your routes.

MiniProfiler.Settings.PopupMaxTracesToShow = 10;

like image 160
Sam Saffron Avatar answered Oct 11 '22 17:10

Sam Saffron