WebApi icon indicating copy to clipboard operation
WebApi copied to clipboard

IN $filter operator not working with open type

Open bonfi7 opened this issue 4 years ago • 7 comments

Filtering open type entity by a property using IN operator not works.

Assemblies affected

Assemblies affected Microsoft.AspNetCore.OData 7.5.2

Reproduce steps

Map odata in Startup.cs

app.UseMvc(routes =>
            {
                routes.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
                routes.SetSerializeNullDynamicProperty(true);
                routes.MapODataServiceRoute("odata", "odata", GetEdmModel());              
            });
...

private static IEdmModel GetEdmModel()
        {
            ODataModelBuilder builder = new ODataModelBuilder();

            EntityTypeConfiguration<DataItem> entityType = builder.EntityType<DataItem>();
            entityType .HasKey(c => c.__id);
            entityType .HasDynamicProperties(c => c.DynamicProperties);
            
            IEdmModel model = builder.GetEdmModel();            

            return model;
        }

Define DataItem class as

 public class DataItem
    {
        public int __id { get; set; }
        public IDictionary<string, object> DynamicProperties { get; set; }
    }

and declare the odata controller as:

public class EntitiesController : ODataController
    {
        [EnableQuery]
        public IActionResult Get()
        {
            List<DataItem> result = new List<DataItem>();
            for (int i = 0; i < 10; i++)
            {
                var item = new DataItem
                {
                    __id = i,
                    DynamicProperties = new Dictionary<string, object>()
                };

                item.DynamicProperties.Add("Id", Guid.NewGuid().ToString());
                item.DynamicProperties.Add("Category", "MyCategory");
                item.DynamicProperties.Add("Index", i);

                result.Add(item);
            }

            return Ok(result.AsQueryable());
            
        }
}

Start the project and call in the browser the:

http://localhost:60760/odata/entities?$filter=Index in (1,2)

Expected result

Filter result with IN operator and obtain filtered data.

{ "@odata.context": "http://localhost:60760/odata/$metadata#Entities", "value": [{ "__id": 1, "Id": "f6227160-36b7-4c6d-8695-627b96dbcbd3", "Category": "MyCategory", "Index": 1 }, { "__id": 2, "Id": "fe8176aa-56aa-441c-a4ea-e0811916699e", "Category": "MyCategory", "Index": 2 } ] }

Actual result

The following excveption is returned: System.ArgumentNullException: Value cannot be null. (Parameter 'elementType') at Microsoft.OData.Edm.EdmUtil.CheckArgumentNull[T](T value, String parameterName) at Microsoft.OData.Edm.EdmCollectionType..ctor(IEdmTypeReference elementType) at Microsoft.OData.UriParser.InBinder.BindInOperator(InToken inToken, BindingState state) at Microsoft.OData.UriParser.MetadataBinder.BindIn(InToken inToken) at Microsoft.OData.UriParser.MetadataBinder.Bind(QueryToken token) at Microsoft.OData.UriParser.FilterBinder.BindFilter(QueryToken filter) at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseFilterImplementation(String filter, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo) at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseFilter() at Microsoft.AspNet.OData.Query.FilterQueryOption.get_FilterClause() at Microsoft.AspNet.OData.Query.Validators.FilterQueryValidator.Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings) at Microsoft.AspNet.OData.Query.FilterQueryOption.Validate(ODataValidationSettings validationSettings) at Microsoft.AspNet.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) at Microsoft.AspNet.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings) at Microsoft.AspNet.OData.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions) at Microsoft.AspNet.OData.EnableQueryAttribute.CreateAndValidateQueryOptions(HttpRequest request, ODataQueryContext queryContext) at Microsoft.AspNet.OData.EnableQueryAttribute.<>c__DisplayClass1_0.<OnActionExecuted>b__1(ODataQueryContext queryContext) at Microsoft.AspNet.OData.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, Func2 modelFunction, IWebApiRequestMessage request, Func2 createQueryOptionFunction) at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func2 modelFunction, Func2 createQueryOptionFunction, Action1 createResponseAction, Action3 createErrorAction) at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext) at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

bonfi7 avatar Nov 13 '20 14:11 bonfi7

The problem is that we use the OData JSON collection deserializer in order to deserialize the collection. We are passing null as the type to that collection, which is causing the exception.

The first step is to see if we can call the deserializer without knowing the type. If we have to specify a type, we may be able to specifiy Edm.Untyped.

The second issue will be whether or not we can bind the untyped collection.

mikepizzo avatar Nov 17 '20 17:11 mikepizzo

@mikepizzo any news on this bug?

bonfi7 avatar Jan 14 '22 10:01 bonfi7

I'm also affected by this issue in one of my project; for us is very annoying because is blocking one relevant feature we would like to introduce. I'll follow the thread.

senex83 avatar Jan 14 '22 11:01 senex83

Hello,

Any updates?

elglogins avatar Mar 31 '22 17:03 elglogins

@mikepizzo @gathogojr any news?

bonfi7 avatar Sep 07 '22 15:09 bonfi7

Hi,

I'm also affected by this issue in one of my projects. Any updates on this @gathogojr?

ovparvu avatar May 12 '23 16:05 ovparvu

Just ran into this issue using the latest OData 8 and Asp.net Core 7 stack. Any news for this issue?

audacity76 avatar Sep 11 '23 08:09 audacity76