Skip to content

Issue with Enum Flags in OData Query Parsing #3244

@WanjohiSammy

Description

@WanjohiSammy

Describe the bug

When querying an OData endpoint that uses a Flags enum, the query fails to parse correctly when using either string representations of combined enum values or their numeric equivalents. This issue arises when attempting to filter data using queries such as /customers?filter=Type eq 'Premium,Loyal' or /customers?filter=Type eq 66. The error indicates that the provided string or numeric value is not recognized as a valid enumeration type constant.

Affected Assemblies

ODL 7.x, 8.x

Steps to Reproduce

  1. Clone the repo:
git clone https://github.com/WanjohiSammy/FlagsEnumIssue.git
  1. Flags enum in the application:

    [Flags]
    public enum CustomerType
    {
         None = 1,
         Premium = 2,
         VIP = 4,
         Regular = 8,
         New = 16,
         Returning = 32,
         Loyal = 64,
    }
  2. A model that uses the Flags enum:

    public class Customer
    {
         public int Id { get; set; }
         public string? Name { get; set; }
         public CustomerType? Type { get; set; }
    }
  3. Query the OData endpoint with the following filters:

    • /customers?filter=Type eq 'Premium,Loyal'
    • /customers?filter=Type eq 66 (where 66 is the result of CustomerType.Premium | CustomerType.Loyal)
    • /customers?filter=Type in ('Premium', 'VIP, Regular, Returning')
    • /customers?filter=Type in (12, 44) (where 12 is CustomerType.Premium | CustomerType.Loyal and 44 is CustomerType.VIP | CustomerType.Regular | CustomerType.Returning)
    • /customers?filter=Type in ('12', '44')
    • /customers?filter=Type has any 'Premium,Loyal'
    • /customers?filter=Type has any '66'

Expected Behavior

The OData query should correctly parse and filter results based on the provided Flags enum values, regardless of whether they are specified as strings or numeric equivalents. For example:

  • /customers?filter=Type eq 'Premium,Loyal' should return customers with the Type field set to CustomerType.Premium | CustomerType.Loyal.
  • /customers?filter=Type eq 66 should return the same results as the above query.

Actual Behavior

The query fails with an error similar to the following:

{
  "error": {
    "code": "",
    "message": "The query specified in the URI is not valid. The string '66' is not a valid enumeration type constant.",
    "details": [],
    "innererror": {
      "message": "The string '66' is not a valid enumeration type constant.",
      "type": "Microsoft.OData.ODataException",
      "stacktrace": "   at Microsoft.OData.UriParser.MetadataBindingUtils.ConvertToTypeIfNeeded(SingleValueNode source, IEdmTypeReference targetTypeReference)\r\n   at Microsoft.OData.UriParser.BinaryOperatorBinder.PromoteOperandTypes(BinaryOperatorKind binaryOperatorKind, SingleValueNode& left, SingleValueNode& right, TypeFacetsPromotionRules facetsPromotionRules)\r\n   at Microsoft.OData.UriParser.ODataUriResolver.PromoteBinaryOperandTypes(BinaryOperatorKind binaryOperatorKind, SingleValueNode& leftNode, SingleValueNode& rightNode, IEdmTypeReference& typeReference)\r\n   at Microsoft.OData.UriParser.BinaryOperatorBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)\r\n   at Microsoft.OData.UriParser.MetadataBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)\r\n   at Microsoft.OData.UriParser.MetadataBinder.Bind(QueryToken token)\r\n   at Microsoft.OData.UriParser.FilterBinder.BindFilter(QueryToken filter)\r\n   at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseFilterImplementation(String filter, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)\r\n   at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseFilter()\r\n   at Microsoft.AspNetCore.OData.Query.FilterQueryOption.get_FilterClause()\r\n   at Microsoft.AspNetCore.OData.Query.Validator.FilterQueryValidator.Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings)\r\n   at Microsoft.AspNetCore.OData.Query.FilterQueryOption.Validate(ODataValidationSettings validationSettings)\r\n   at Microsoft.AspNetCore.OData.Query.Validator.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n   at Microsoft.AspNetCore.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)\r\n   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuting(ActionExecutingContext actionExecutingContext)"
    }
  }
}

Additional Details

The issue appears to stem from the following sections of the Microsoft.OData.Core library:

These sections of code may need to be updated to handle Flags enums more effectively, ensuring that both string and numeric representations of combined enum values are correctly parsed and validated.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions