-
Notifications
You must be signed in to change notification settings - Fork 711
CORS preflight request with URL Path versioning results in ArgumentNullException
#619
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
Comments
Minimal repro solution: CorsVersioningExample.zip
|
Thanks for the repro. I was able to recreate your conditions. It took some digging and debugging, but I was able to track down where the problem occurs. It actually comes from the CORS library itself. For some reason it's doing something that it definitely should not: AttributeBasedPolicyProviderFactory (Line 49) The request pipeline uses the Flyweight pattern to pass the request around as a monad. You can see from this referenced code, however, that the CORS library is creating an entirely new request and forwarding it on. The comments claim that this is done due to things in the request property bag that shouldn't be passed along (but I don't know why). IMO, if this is really required, then the properties should be removed, the original request forwarded, and then re-add the properties after the return. This would maintain the monad. This behavior breaks API Versioning, specifically, in the case of versioning by URL segment (which I don't recommend). This is because the only time API Versioning knows which route parameter value contains the API version is when the ApiVersionRouteConstraint is evaluated. When the route constraint matches, it gets or adds the ApiVersioningProperties from the request's property bag. Since there are two different request instances, there are two different property bags and two different sets of ApiVersioningProperties, one of whom does not have the API version because it wasn't the one used by the route constraint. Ultimately, this is a sequencing problem in the CORS library design.
Honestly, I feel like this is a bug in the CORS library as I don't see any real compelling reason why a new request has to be created. This is certainly not something that extensions would expect to encounter. I only discovered this was the case by first noticing the property was missing later in the pipeline and that the hash code of the request objects didn't match at different points in the pipeline. Ideally, it would be great if API Versioning can handle this situation, despite it being something that should never happen. I'm not sure what that solution is yet and it may take a little bit. In the meantime, there are at least two possible workarounds:
Probably not the answers your hoping for, but that will hopefully unblock you while something more out-of-the-box is evaluated. BTW: I noticed you had a lot of conflicting and unnecessary transitive dependencies in your repro. To use Autofac with the latest OWIN and Web API stacks, you need to target .NET 4.6.1. I'm not sure if there's a reason why you can't, but there are warnings of conflicting versions. You also don't need to list all of your transitive dependencies. The following subset resolves the same references: <PropertyGroup>
<TargetFramework>net461</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac.WebApi2.Owin" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Cors" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNet.WebApi.Versioning.ApiExplorer" Version="4.0.0" />
<PackageReference Include="Microsoft.Owin.Security.Jwt" Version="4.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Owin.Logging.Common" Version="1.0.5506.19675" />
</ItemGroup> |
Thanks @commonsensesoftware for this amazingly quick & comprehensive response. I'll need a bit of time to digest this & work out what to do. |
A quick follow up. I looked at this just a bit more. The new request is definitely the culprit, but I figured out exactly why. AttributeBasedPolicyProviderFactory.cs (Line 72) does not account for I need to test and flush out whether it's the right thing, but it looks like I can tell if this has happened in a generic way by checking for the presence of the If I'm right, this means the ApiVersioningProperties extension method can change to something like this: public static ApiVersionRequestProperties ApiVersionProperties(this HttpRequestMessage request)
{
if ( request == null )
{
throw new ArgumentNullException( nameof( request ) );
}
if ( !request.Properties.TryGetValue(
ApiVersionPropertiesKey,
out ApiVersionRequestProperties properties ) )
{
// assume route constraints haven't been evaluated if this key isn't present
var forceRouteConstraintEvaluation =
!request.Properties.ContainsKey( RoutingContextKey );
// add to the property bag FIRST because the ApiVersionRouteConstraint will re-enter,
// resulting in StackOverflowException
request.Properties[ApiVersionPropertiesKey] = properties =
new ApiVersionRequestProperties( request );
if ( forceRouteConstraintEvaluation )
{
// now force evaluation; reentrancy is safe at this point
request.GetConfiguration().Routes.GetRouteData( request );
}
}
return properties;
} Testing against your repro seemed to behave as expected. I'll need to put this against the full suite, but hopefully I can get this patched in the next day or two. In the meantime, the other workarounds are still applicable. |
Checking back in. Did the workaround work for you? I've incorporated my proposed generic solution, but it won't go out until the next release. If the workaround worked for you, I'll close this issue so I know it's complete and add the details to the release notes. Thanks. |
Hi @commonsensesoftware. We ended up going with a different method of versioning. When you've released the fix we'll reconsider whether to revert to the original approach. Thanks for checking in. |
Thanks for confirming. I'll mark this is an answered, but leave it open. It will auto-close once the changes are merged. That will be time to consider/reconsider incorporating things. Glad you got something working. |
This is now fixed in 4.1.0-RC.1. The RC is just status parity with the other libraries at the moment. The official release should happen shortly after a little burn-in; probably 2 weeks. There's no additional work or fixes expected to go in. If the issue remains, feel free to reopen the issue or open a new one. Thanks for helping track down the issue. |
Uh oh!
There was an error while loading. Please reload this page.
I have a .NET Framework 4.5 project using OWIN & ASP.NET Web API, with CORS support using
Microsoft.AspNet.WebApi.Cors
. Runtime is Mono 6.x.When I add URL Path versioning, preflight requests fail with
ArgumentNullException
:Value cannot be null.\nParameter name: response
, and stackThe text was updated successfully, but these errors were encountered: