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
- Clone the repo:
git clone https://github.com/WanjohiSammy/FlagsEnumIssue.git
-
Flags enum in the application:
[Flags]
public enum CustomerType
{
None = 1,
Premium = 2,
VIP = 4,
Regular = 8,
New = 16,
Returning = 32,
Loyal = 64,
}
-
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; }
}
-
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.
Describe the bug
When querying an OData endpoint that uses a
Flagsenum, 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
Flagsenum in the application:A model that uses the
Flagsenum:Query the OData endpoint with the following filters:
/customers?filter=Type eq 'Premium,Loyal'/customers?filter=Type eq 66(where 66 is the result ofCustomerType.Premium | CustomerType.Loyal)/customers?filter=Type in ('Premium', 'VIP, Regular, Returning')/customers?filter=Type in (12, 44)(where 12 isCustomerType.Premium | CustomerType.Loyaland 44 isCustomerType.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
Flagsenum values, regardless of whether they are specified as strings or numeric equivalents. For example:/customers?filter=Type eq 'Premium,Loyal'should return customers with theTypefield set toCustomerType.Premium | CustomerType.Loyal./customers?filter=Type eq 66should 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.Corelibrary:MetadataBindingUtils.cslines 63-81MetadataBindingUtils.cslines 199-209These sections of code may need to be updated to handle
Flagsenums more effectively, ensuring that both string and numeric representations of combined enum values are correctly parsed and validated.