Skip to content
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

AutoExpand not working correctly with $Expand uri query parameters #1284

Open
timClyburn opened this issue Jul 16, 2024 · 3 comments · Fixed by #1292
Open

AutoExpand not working correctly with $Expand uri query parameters #1284

timClyburn opened this issue Jul 16, 2024 · 3 comments · Fixed by #1292
Assignees
Labels
bug Something isn't working P3

Comments

@timClyburn
Copy link

timClyburn commented Jul 16, 2024

Assemblies affected
Microsoft.AspNetCore.OData version 8.2.5

Describe the bug
According to OASIS docs, system query options must support case-insensitive system query option names with or without a $ prefix.

When using AutoExpand or AutoSelect, and specifying a matching system query option that's not lower case (such as $Expand) an exception is thrown. The exception indicates that Expand is being added twice.

{
    "error": {
        "code": "",
        "message": "The query specified in the URI is not valid. Query option '$expand/expand' was specified more than once, but it must be specified at most once.",
        "details": [],
        "innererror": {
            "message": "Query option '$expand/expand' was specified more than once, but it must be specified at most once.",
            "type": "Microsoft.OData.ODataException",
            "stacktrace": "   at Microsoft.OData.UriParser.ODataQueryOptionParser.TryGetQueryOption(String name, String& value)\r\n   at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseSelectAndExpand()\r\n   at Microsoft.AspNetCore.OData.Query.SelectExpandQueryOption.ProcessLevels()\r\n   at Microsoft.AspNetCore.OData.Query.SelectExpandQueryOption.get_ProcessedSelectExpandClause()\r\n   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.ApplySelectExpand[T](T entity, ODataQuerySettings querySettings)\r\n   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.ApplyTo(IQueryable query, ODataQuerySettings querySettings)\r\n   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)\r\n   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)"
        }
    }
}

I have managed to track the error to the function AddAutoSelectExpandProperties within Microsoft.AspNetCore.Odata.Query.OdataQueryOptions.cs.

	internal void AddAutoSelectExpandProperties()
	{
		bool containsAutoSelectExpandProperties = false;
		string autoExpandRawValue = GetAutoExpandRawValue();
		string autoSelectRawValue = GetAutoSelectRawValue();
		IDictionary<string, string> queryParameters = GetODataQueryParameters();
		if (!string.IsNullOrEmpty(autoExpandRawValue) && !autoExpandRawValue.Equals(RawValues.Expand, StringComparison.Ordinal))
		{
			queryParameters["$expand"] = autoExpandRawValue;
			containsAutoSelectExpandProperties = true;
		}
		else
		{
			autoExpandRawValue = RawValues.Expand;
		}
		if (!string.IsNullOrEmpty(autoSelectRawValue) && !autoSelectRawValue.Equals(RawValues.Select, StringComparison.Ordinal))
		{
			queryParameters["$select"] = autoSelectRawValue;
			containsAutoSelectExpandProperties = true;
		}
		else
		{
			autoSelectRawValue = RawValues.Select;
		}
		if (containsAutoSelectExpandProperties)
		{
			_queryOptionParser = new ODataQueryOptionParser(Context.Model, Context.ElementType, Context.NavigationSource, queryParameters, Context.RequestContainer);
			SelectExpandQueryOption originalSelectExpand = SelectExpand;
			SelectExpand = new SelectExpandQueryOption(autoSelectRawValue, autoExpandRawValue, Context, _queryOptionParser);
			if (originalSelectExpand != null && originalSelectExpand.LevelsMaxLiteralExpansionDepth > 0)
			{
				SelectExpand.LevelsMaxLiteralExpansionDepth = originalSelectExpand.LevelsMaxLiteralExpansionDepth;
			}
			else if (Context.ValidationSettings != null && Context.ValidationSettings.MaxExpansionDepth > 0)
			{
				SelectExpand.LevelsMaxLiteralExpansionDepth = Context.ValidationSettings.MaxExpansionDepth;
			}
		}
	}

The line below explicitly adds the auto expanded path values to the queryParameters dictionary with the key "$expand", in the case that the query parameters are also in lower case, this works, but if the query parameters are "$Expand", for example, instead of overriding the parameter a second queryParameter is added.

queryParameters["$expand"] = autoExpandRawValue;

The simple solution may be to ensure that the query parameter is always in lower case...

private IDictionary<string, string> GetODataQueryParameters()
  {
      Dictionary<string, string> result = new Dictionary<string, string>();

      foreach (var query in Request.Query)
      {
          string key = query.Key.Trim().ToLower();
          string value = query.Value.ToString();

      // code removed for brevity
      ...
     }
     return result;
}

Expected behavior
This shouldn't error and case on the Expand or Select query parameters should not matter.

@WanjohiSammy
Copy link

@timClyburn Could you provide the sample example of AutoSelect that is failing and share the error message.
I am able to reproduce this issue for AutoExpand but not for AutoSelect

@timClyburn
Copy link
Author

@timClyburn Could you provide the sample example of AutoSelect that is failing and share the error message. I am able to reproduce this issue for AutoExpand but not for AutoSelect

@WanjohiSammy I don't have an example for the AutoSelect, the issue was identified when using AutoExpand, but since they both shared the same function for generating the query I included both.

@WanjohiSammy
Copy link

@WanjohiSammy I don't have an example for the AutoSelect, the issue was identified when using AutoExpand, but since they both shared the same function for generating the query I included both.

@timClyburn Is it okay to update the title to something like this: AutoExpand not working correctly with $Expand uri query parameters

@timClyburn timClyburn changed the title AutoExpand and AutoSelect not working correctly with $Expand and $Select uri query parameters AutoExpand not working correctly with $Expand uri query parameters Sep 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working P3
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants