Skip to content

string[] bound to querystring in minimal API should return 400 when not present #45956

Description

@andrewlock

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When you have a minimal API that takes a string[] (or StringValues) parameter which binds to the querystring, for example:

app.MapGet("/", (string[] q) => q);

calling the API without a querystring (e.g. /) should give a 400 response saying BadHttpRequestException: Required parameter "string[] q" was not provided from query string.

But this does not happen - instead q is an empty array. This differs from both of the following other examples:

app.MapGet("/", (string q) => q); //
app.MapGet("/", (StringValues q) => q); 

which both return a 400 response as expected.

Expected Behavior

When binding a required parameter in a minimal API, a value must be present in the binding source (typically the querystring when binding arrays), otherwise the API returns a 400. This is the documented behaviour which works for other parameter types.

Steps To Reproduce

To reproduce, create an api like this: app.MapGet("/", (string[] q) => q); and call the URL / (without a querystring). The response is [], where it should be a 400 Bad Request.

Exceptions (if any)

No response

.NET Version

7.0.101

Anything else?

I found this behaviour while reading some of the Expression generation code in RequestDelegateFactory. In particular CreateArgument() calls BindParameterFromValue which calls BindParameterFromExpression.

The argument expression generated by this code when binding a string[] parameter (called q in this example) to the querystring is similar to the following (some artisitic license):

Task Invoke(HttpContext httpContext)
{
    bool wasParamCheckFailure = false; // Added by RequestDelegateFactory.Create()

    string[] q_local = httpContext.Request.Query["q"] // 👈 This is the problem
    if (q_local == null) // 👈 Because this is never true.
    {
        wasParamCheckFailure = true;
        Log.RequiredParameterNotProvided(httpContext, "string[]", "q", "query");
    }

    if(wasParamCheckFailure) // Added by RequestDelegateFactory.Create()
    {
        httpContext.Response.StatusCode = 400;
        return Task.CompletedTask;
    }

    // .. call handler, handle response
}

I think the problem lies in the line above. Query["q"] returns StringValues.Empty when the item is not present, and is implicitly converted to a string[]. (string[])StringValues.Empty always returns an empty array, so is never null, so the check never succeeds.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions