-
Notifications
You must be signed in to change notification settings - Fork 475
Description
As brought up by #1616, CreateRequestContainer throws an InvalidOperationException when it's called multiple times. In the case of multiple routes being matched by the RouteConstraintMatcher for multiple ApiVersions, the exception here gets thrown if a higher version is requested, and it eventually gets swallowed. Even though it doesn't cause the request to fail, the problem is we have found it has caused an increased in lock contention and CPU usage in one of our high traffic services due to excess cost of the exceptions being thrown.
Assemblies affected
Microsoft.AspNetCore.OData 7.5.17
Reproduce steps
- Configure multiple routes using the ApiVersioning library, for example: https://github.com/dotnet/aspnet-api-versioning/blob/v4.1.0/samples/aspnetcore/ODataBasicSample/Configuration/PersonModelConfiguration.cs
- Set a breakpoint at the location where the InvalidOperationException is thrown
- Make a request to the service that requests the higher version
- Expect CreateRequestContainer to be invoked for each versioned route starting from the lowest version
Expected result
No InvalidOperationException is thrown at all.
Actual result
InvalidOperationException is thrown then swallowed.
Additional detail
Here are some stack details:
Exception stack
Microsoft.AspNetCore.Builder.RouterMiddleware!Invoke
System.Runtime.CompilerServices.AsyncMethodBuilderCore!Start
Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4!MoveNext
Microsoft.AspNetCore.Routing.RouteCollection!RouteAsync
System.Runtime.CompilerServices.AsyncMethodBuilderCore!Start
Microsoft.AspNetCore.Routing.RouteCollection+<RouteAsync>d__10!MoveNext
Microsoft.AspNetCore.Routing.RouteBase!RouteAsync
Microsoft.AspNetCore.Routing.RouteConstraintMatcher!Match
Microsoft.AspNet.OData.Routing.VersionedODataPathRouteConstraint!Match
Microsoft.AspNet.OData.Routing.ODataPathRouteConstraint!Match
Microsoft.AspNet.OData.Extensions.HttpRequestExtensions!CreateRequestContainer
coreclr.dll!IL_Throw
coreclr.dll!RaiseTheExceptionInternalOnly
KernelBase.dll!RaiseException
ntdll.dll!RtlRaiseException
ntdll.dll!RtlDispatchException
ntdll.dll!RtlpExecuteHandlerForException
coreclr.dll!ProcessCLRException
coreclr.dll!ExceptionTracker::ProcessOSExceptionNotification
coreclr.dll!ExceptionTracker::ProcessManagedCallFrame
coreclr.dll!`coreclr_initialize'::`13'::`dynamic atexit destructor for 'bundle''
coreclr.dll!FireEtwExceptionThrown_V1
coreclr.dll!McTemplateCoU0zzpqhh_EventWriteTransfer
coreclr.dll!McGenEventWrite_EventWriteTransfer
ntdll.dll!EtwEventWriteTransfer
ntdll.dll!EtwpEventWriteFull
ntdll.dll!ZwTraceEvent
System.InvalidOperationException
Lock contention from walking the stack, which could be due to the high rate of exceptions.
ntoskrnl.exe!RtlBackoff
ntoskrnl.exe!ExfAcquirePushLockSharedEx
ntoskrnl.exe!ExAcquirePushLockSharedEx
ntoskrnl.exe!RtlpLookupUserFunctionTable
ntoskrnl.exe!RtlpLookupFunctionEntryForStackWalks
ntoskrnl.exe!RtlpWalkFrameChain
ntoskrnl.exe!RtlWalkFrameChain
ntoskrnl.exe!EtwpTraceStackWalk
ntoskrnl.exe!EtwpStackWalkApc
ntoskrnl.exe!KiDeliverApc
ntoskrnl.exe!KiApcInterrupt
ntoskrnl.exe!KeYieldExecution
ntoskrnl.exe!NtYieldExecution