Skip to content

LockRecursionException after update #703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
EdwardFinn opened this issue Nov 30, 2020 · 7 comments
Closed

LockRecursionException after update #703

EdwardFinn opened this issue Nov 30, 2020 · 7 comments

Comments

@EdwardFinn
Copy link

Updating via Nuget from Microsoft.AspNet.WebApi.Versioning 4.0.0 to 4.1.0 results in System.Threading.LockRecursionException

Error is thrown from
System.Web.Http.HttpRequestMessageExtensions.ApiVersionProperties( this HttpRequestMessage request )

System.Threading.LockRecursionException
  HResult=0x80131500
  Message=Recursive read lock acquisitions not allowed in this mode.
  at System.Threading.ReaderWriterLockSlim.TryEnterReadLockCore(TimeoutTracker timeout)
    at System.Threading.ReaderWriterLockSlim.TryEnterReadLock(TimeoutTracker timeout)
    at System.Web.Routing.RouteCollection.GetReadLock()
    at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext)
    at System.Web.Http.WebHost.Routing.HostedHttpRouteCollection.GetRouteData(HttpRequestMessage request)
    at System.Web.Http.HttpRequestMessageExtensions.ApiVersionProperties(HttpRequestMessage request)
    at Microsoft.Web.Http.Routing.ApiVersionRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, String parameterName, IDictionary`2 values, HttpRouteDirection routeDirection)
    at System.Web.Http.WebHost.Routing.HttpWebRoute.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 System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext)

configuration is by namespace

            DefaultInlineConstraintResolver constraintResolver = new DefaultInlineConstraintResolver()
            {
                ConstraintMap = {
                                    ["apiVersion"] = typeof( ApiVersionRouteConstraint )
                                }
            };
            config.MapHttpAttributeRoutes(constraintResolver);
            config.AddApiVersioning(options =>
            {
                options.ReportApiVersions = true;
                options.Conventions.Add(new VersionByNamespaceConvention());
            });

            //Change default route to include api version
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "v{apiVersion}/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional },
                constraints: new { apiVersion = new ApiVersionRouteConstraint() }
            );

And not sure its if matters but version is single number

namespace Test.API.Controllers.v1
{
    [RoutePrefix("v{version:apiVersion}/GlobalSettings")]
    public class GlobalSettingsController : ApiController
    {
        [HttpGet]
        public string GetSetting(string key)
        {
            return "TEST";
        }

    }
}
@commonsensesoftware
Copy link
Collaborator

This is strange. I've never seen this. Does this happen all the time or only some of the time? I can't think of any change that would cause this and not be caught in some form of testing. How are you hosting? IIS? self-host? I've seen different hosts cause issues and I don't the resource to test on every host.

Thanks

@EdwardFinn
Copy link
Author

EdwardFinn commented Nov 30, 2020

IIS express from Visual Studio 2017 or 2019 on two separate windows 10 pc's.
It occurs for every single request.
It was discovered during creation of a new project, so the code I pasted are about the only changes made to a .Net 4.6.2 webapi project. I can't upload this project, but if it would help I can create a new project, reproduce and attach.

@commonsensesoftware
Copy link
Collaborator

A repro with all the setup and configuration you used is always best. It's not supposed to matter, but there are edge cases where the hosting model causes variations. I've had a few such edge cases with IIS and/or IIS Express. I've moved away from them for testing and samples to more closely align between Classic ASP.NET and ASP.NET Core. The self-host approach also executes much faster with far less configuration.

@EdwardFinn
Copy link
Author

Here you go, confirmed same error on both my windows 10 iis express in vs2019, and on server 2012 r2 iis 8.5
Test_703.zip

@MikeBKemp
Copy link

MikeBKemp commented Mar 8, 2021

I also have this issue with version 4.1.1, but only if I use the constraints parameter of MapHttpRoute. If I instead use a Route attribute on the controller, it works fine. Hosted on Windows 10 IIS, VS 2019.

@grdlbumpf
Copy link

grdlbumpf commented Apr 13, 2021

Any news on this one. Same issue here. 4.1.1
with .net 4.7.2 windows 10 iis-express. vs 2019

EDIT: downgraded to 4.0.0 temporarily (which IS working)

@commonsensesoftware
Copy link
Collaborator

Apologies. Apparently, I missed this issue during sweeping status updates the past couple of weeks.

I thought this was perhaps related to #705, but after further analysis, I don't think it is. This issue appears to be caused by an update that adds explicit route value evaluation here. This only happens when hosted using the IIS implementation (which is infuriating 😠). This would be the 4th or 5th time there has been a runtime difference in hosts.

There isn't a clear and straight forward way to determine whether GetRouteData will result in an exception. Reverting the change will likely regress the original issue. The best course would seem to wrap this with a try...catch. If an exception is throw when hosted on IIS, it can be safely ignored.

I need to confirm that will work with the provided repro, but I suspect that it will.

TL;DR

@EdwardFinn I also noticed that you are mixing convention and attribute-based routing methods. I strongly advise against that; especially in Web API. Attribute-based routing was bolted on after the fact. Mixing the two can lead to a lot of confusion for debugging and maintenance. The example you provided just so happens to illustrate this problem.

The following appears to use attribute-routing, but insufficient attributes have been provided. Since a convention has been defined, the routing system will fall back and match a convention-based route pattern. This is a false negative as it should have failed.

    [RoutePrefix("v{version:apiVersion}/GlobalSettings")] // ← a prefix is defined, but this attribute does nothing!
    public class GlobalSettingsController : ApiController
    {
        [HttpGet]
        // TODO: for this to use attribute routing, you need the following attribute:
        // [Route("{key}")]
        public string GetSetting(string key) => "TEST";  // ← this action is actually routed by convention
                                                         // also note that 'key' will always be null because the
                                                         // expected parameter name is 'id' in your route template
    }

The repro appears to Web API and MVC together. That's fine, but remember that they each their own routing systems. You can elect to only use attribute routing in Web API, while only using convention-based routing in MVC.

You can mix styles if you really want to, but be warned - there be dragons. There are certain edge cases where API Versioning will not work properly. As long as you don't mix routing styles between controllers logically grouped together across versions, you should be fine. This issue is most pervasive when using Web API with OData.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants