LockRecursionException: Write lock may not be acquired with read lock held

We ran into this error recently. I wanted to report it to ensure someone could review due the seriousness of it’s nature.

 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 StackExchange.Profiling.UI.MiniProfilerHandler.RegisterRoutes()
    at <snip />.<snip />()
    at <snip />.<<snip />Cache>b__1()
    at <snip />ObjectCacheProvider.Get[ITEM_TYPE](String key, CacheItemPolicy policy, Func`1 getItem)
    at <snip />.Get(String url)
    at <snip />RouteConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    at System.Web.Routing.Route.ProcessConstraint(HttpContextBase httpContext, Object constraint, String parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    at System.Web.Routing.Route.ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
    at System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext)
    at <snip />Route.GetRouteData(HttpContextBase httpContext)
    at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext)
    at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
    at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

To reproduce you create a IRouteConstraint use it to evaluate a MVC route then within the Match method call the Step extension method for the MiniProfiler.Current property.

Richard

PS – Looks like it could be an issue with System.Web.Routing.RouteCollection.GetWriteLock method. It’s not properly upgrading the lock.

UPDATE: I noticed this behavior is caused when the code is called within a IRouteConstraint during the evaluation of Routes. The scenario seems to be the Step method is called within this code block can cause the issue. I’m still not convinced it’s an issue with MiniProfiler, but rather an issue with System.Web.Routing.RouteCollection.GetWriteLock method.

UPDATE: It’s caused when the RegisterRoutes is called. Seems the simplest way to solve this is to force the RegisterRoutes to run once and done on start. Any thoughts?

Create a IRouteConstraint use it to evaluate a MVC route then within the Match method call the Step extension method for the MiniProfiler.Current property.