Skip to content

RDF/RDG inconsistency when resolving query/route parameters. #47353

@mitchdenny

Description

@mitchdenny

The test case NullRouteParameterPrefersRouteOverQueryString highlights an error with the way that we resolve whether a parameter comes from route values or query strings.

The original test case code looks like this:

    [Fact]
    public async Task NullRouteParametersPrefersRouteOverQueryString()
    {
        var httpContext = CreateHttpContext();

        var factoryResult = RequestDelegateFactory.Create((int? id, HttpContext httpContext) =>
        {
            if (id is not null)
            {
                httpContext.Items["input"] = id;
            }
        },
        new() { RouteParameterNames = null });

        httpContext.Request.Query = new QueryCollection(new Dictionary<string, StringValues>
        {
            ["id"] = "41"
        });
        httpContext.Request.RouteValues = new()
        {
            ["id"] = "42"
        };

        var requestDelegate = factoryResult.RequestDelegate;
        await requestDelegate(httpContext);

        Assert.Equal(42, httpContext.Items["input"]);
    }

Coverted to the shared RDF/RDG test infrastructure, it looks like this:

    [Fact]
    public async Task NullRouteParametersPrefersRouteOverQueryString()
    {
        var (_, compilation) = await RunGeneratorAsync($$"""
  app.MapGet(@"/", (int? id, HttpContext httpContext) => {
    if (id is not null)
    {
        httpContext.Items["input"] = id;
    }
  });
  """);
        var endpoint = GetEndpointFromCompilation(compilation);

        var httpContext = CreateHttpContext();

        httpContext.Request.Query = new QueryCollection(new Dictionary<string, StringValues>
        {
            ["id"] = "41"
        });
        httpContext.Request.RouteValues = new()
        {
            ["id"] = "42"
        };

        var requestDelegate = endpoint.RequestDelegate;
        await requestDelegate(httpContext);

        Assert.Equal(42, httpContext.Items["input"]);
    }

The coverted test case fails in both RDF and RDG, but the reasons are subtle. The original test case doesn't need to provide an actual route pattern. It triggers some fallback behavior in RDG where even if the route pattern doesn't include a route parameter it still checks to see whether the RouteValues dictionary has a property defined which matches the parameter on the delegate - if so; it prefers it over the query string.

The reason this doesn't work in RDG is that we resolve whether to pull parameter values from either route values or query string based on the route parameter names present in the pattern.

This test case is interesting because it checks on some internal behaviors of RDF, but its not really a scenario we can reproduce in RDG (nor can we trigger the same behavior with RDF in the new test infrastructure).

Metadata

Metadata

Assignees

Labels

area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-rdg

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions