Webapi: Optional parameter not working for function with single argument

Created on 12 Nov 2018  Â·  8Comments  Â·  Source: OData/WebApi

When defining a function with single optional parameter, api returns 500 (Internal Server Error).

Assemblies affected

Microsoft.AspNet.OData 7.0.1

Reproduce steps

[ODataRoute("Users/GetFirstName()")]
public string GetFirstName()
{
    return GetFirstName("Unknown");
}

[ODataRoute("Users/GetFirstName(firstName={firstName})")]
public string GetFirstName(string firstName)
{
    return firstName;
}
var getFirstName = builder.EntityType<User>().Collection
    .Function("GetFirstName")
    .Returns<string>();

getFirstName.Parameter<string>("firstName").Optional().HasDefaultValue("Unknown");

Request

http://localhost:63000/v1/Users/GetFirstName()

Expected result

{
    "@odata.context": "http://localhost:63000/v1/$metadata#Edm.String",
    "value": "Unknown"
}

Actual result

Status: 500 Internal Server Error

Server Error in '/' Application.

The path template 'Users/GetFirstName()' on the action 'GetFirstName' in controller 'Users' is not a valid OData path template. Bad Request - Error in query syntax.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The path template 'Users/GetFirstName()' on the action 'GetFirstName' in controller 'Users' is not a valid OData path template. Bad Request - Error in query syntax.

Additional detail

Example: https://github.com/flibustier7seas/odata-example/tree/optional-parameter#optional-parameter-not-working-for-function-with-single-argument

investigating

Most helpful comment

Running Microsoft.AspNetCore.OData 7.1.0 I confirm the same buggy behavior as originally described:

  • A single optional parameter is always required in the route

Expected 200 in these scenarios:

  • parts/GetSearchFilterOperators
  • parts/GetSearchFilterOperators()
  • parts/GetSearchFilterOperators(filter=null)

Only scenario that works is the last one, the first two return 404:

2019-03-28 05_12_20-Insomnia – Parts
2019-03-28 05_12_52-Insomnia – Parts
2019-03-28 05_12_39-Insomnia – Parts

Method signature:

[ODataRoute("GetSearchFilterOperators(filter={filter})")]
[HttpGet]
[Produces("application/json")]
[ProducesResponseType(typeof(ODataValue<IEnumerable<SearchFilterOperator>>), (int)HttpStatusCode.OK)]
public IQueryable<SearchFilterOperator> GetSearchFilterOperators([FromODataUri] string filter = null)

ODATA config for the function:

var getSearchFilerOperatorFunc = entityType.Collection
    .Function("GetSearchFilterOperators")
    .ReturnsCollection<SearchFilterOperator>();

var filterParam = getSearchFilerOperatorFunc.Parameter<string>("filter");
filterParam.Optional();
filterParam.HasDefaultValue(null);

All 8 comments

@flibustier7seas Optional parameter means the parameter maybe has default value. But for the function syntax, all parameters (include optional parameters) should be presented in the route template.

In your scenario, you should remove the first one and keep/change the second one as:
C# [ODataRoute("Users/GetFirstName(firstName={firstName})")] public string GetFirstName([FromODataUri]string firstName = "Unknown") { return firstName; }

Hope it can help. Thanks.

@xuzhg

But for the function syntax, all parameters (include optional parameters) should be presented in the route template.

I can skip optional parameters in the route template for function with 2 parameters:

Request: http://localhost:63000/v1/Users/GetFullName(firstName='Foo')

var getFullName =  builder.EntityType<User>().Collection
    .Function("GetFullName")
    .Returns<string>();
getFullName.Parameter<string>("firstName").Required();
getFullName.Parameter<string>("lastName").Optional().HasDefaultValue("Unknown");
[ODataRoute("Users/GetFullName(firstName={firstName})")]
public string GetFullName(string firstName)
{
    return GetFullName(firstName, "Unknown");
}

Why cannot skip optional parameter in the route template for function with single optional parameter?

@flibustier7seas In my understanding, "optional" means its value can be optional, but not for the syntax. for a function or action, its syntax is function name plus the parameter type. That's different with the "method" in C#. I would like @mikepizzo can share his thoughts about the "optional"

@xuzhg
In my understanding, when a parameter is marked as "optional", it can be omitted when the function is called, as in "C#"

https://www.odata.org/blog/OData-401-Committee-Spec-Published/

Optional Function Parameters – Function parameters can be annotated as optional. Optional parameters may be omitted when invoking the function.

@raheph @xuzhg @mikepizzo any updates on this issue?

Any updates? Following.

@denious It should be fixed in the ODL. Would you please try the latest version and share us your finding. Thanks

Running Microsoft.AspNetCore.OData 7.1.0 I confirm the same buggy behavior as originally described:

  • A single optional parameter is always required in the route

Expected 200 in these scenarios:

  • parts/GetSearchFilterOperators
  • parts/GetSearchFilterOperators()
  • parts/GetSearchFilterOperators(filter=null)

Only scenario that works is the last one, the first two return 404:

2019-03-28 05_12_20-Insomnia – Parts
2019-03-28 05_12_52-Insomnia – Parts
2019-03-28 05_12_39-Insomnia – Parts

Method signature:

[ODataRoute("GetSearchFilterOperators(filter={filter})")]
[HttpGet]
[Produces("application/json")]
[ProducesResponseType(typeof(ODataValue<IEnumerable<SearchFilterOperator>>), (int)HttpStatusCode.OK)]
public IQueryable<SearchFilterOperator> GetSearchFilterOperators([FromODataUri] string filter = null)

ODATA config for the function:

var getSearchFilerOperatorFunc = entityType.Collection
    .Function("GetSearchFilterOperators")
    .ReturnsCollection<SearchFilterOperator>();

var filterParam = getSearchFilerOperatorFunc.Parameter<string>("filter");
filterParam.Optional();
filterParam.HasDefaultValue(null);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

LianwMS picture LianwMS  Â·  5Comments

suadev picture suadev  Â·  3Comments

abkmr picture abkmr  Â·  3Comments

VikingsFan picture VikingsFan  Â·  5Comments

davidmorissette picture davidmorissette  Â·  3Comments