AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

Open Type leads to ArgumentNullException: Value cannot be null. (Parameter 'edmType') and NullReferenceException

Open Tvde1 opened this issue 4 months ago • 0 comments

Assemblies affected Tested with Microsoft.AspNetCore.OData Version="8.2.5" and Microsoft.AspNetCore.OData Version="9.0.0". Other versions are possibly also affected.

Describe the bug When working with an open EDM type. Certain queries which are allowed for known properties are not working for unknown properties.

Reproduce steps

See the repro repo for more information and runnable code: https://github.com/Tvde1/ODataOpenTypeRepro/tree/main

The queries

knownString eq 'test'
knownComplexTypeArray/any(x: x/fileName in ('test.txt', 'test2.txt'))
unknownString eq 'test'
unknownInt eq 123
unknownDateTime eq 2024-01-01T00:00:00Z
knownString in ('a', 'b', 'c')
knownInt in (1, 2, 3)

all work, but the following queries all result in crashes internal to the library:

unknownComplexTypeArray/any(x: x/fileName eq 'test.txt')
System.ArgumentNullException: Value cannot be null. (Parameter 'edmType')
   at Microsoft.AspNetCore.OData.Edm.IODataTypeMapperExtensions.GetClrType(IODataTypeMapper mapper, IEdmModel edmModel, IEdmTypeReference edmType, IAssemblyResolver assembliesResolver)
   at Microsoft.AspNetCore.OData.Edm.EdmClrTypeMapExtensions.GetClrType(IEdmModel edmModel, IEdmTypeReference edmTypeReference, IAssemblyResolver assembliesResolver)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinderContext.HandleLambdaParameters(IEnumerable`1 rangeVariables)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.BindAnyNode(AnyNode anyNode, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.BindSingleValueNode(SingleValueNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.Bind(QueryNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.FilterBinder.BindFilter(FilterClause filterClause, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.BinderExtensions.ApplyBind(IFilterBinder binder, IQueryable query, FilterClause filterClause, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.FilterQueryOption.ApplyTo(IQueryable query, ODataQuerySettings querySettings)
   at Program.<<Main>$>g__CreateQuery|0_0[TModel](ODataQueryContext oDataContext, String rule) in C:\temp\ODataOpenTypeRepro\ODataOpenTypeRepro\Program.cs:line 65
   at Program.<Main>$(String[] args) in C:\temp\ODataOpenTypeRepro\ODataOpenTypeRepro\Program.cs:line 42
unknownString in ('a', 'b', 'c')
System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.BindCollectionConstantNode(CollectionConstantNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.BindCollectionNode(CollectionNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.Bind(QueryNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.BindInNode(InNode inNode, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.BindSingleValueNode(SingleValueNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.QueryBinder.Bind(QueryNode node, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.FilterBinder.BindFilter(FilterClause filterClause, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.Expressions.BinderExtensions.ApplyBind(IFilterBinder binder, IQueryable query, FilterClause filterClause, QueryBinderContext context)
   at Microsoft.AspNetCore.OData.Query.FilterQueryOption.ApplyTo(IQueryable query, ODataQuerySettings querySettings)
   at Program.<<Main>$>g__CreateQuery|0_0[TModel](ODataQueryContext oDataContext, String rule)
   at Program.<Main>$(String[] args)
unknownInt in (1, 2, 3)
Microsoft.OData.ODataException: String item should be single/double quoted: '1'.
   at Microsoft.OData.UriParser.InBinder.NormalizeStringCollectionItems(String literalText)
   at Microsoft.OData.UriParser.InBinder.GetCollectionOperandFromToken(QueryToken queryToken, IEdmTypeReference expectedType, IEdmModel model)
   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.AspNetCore.OData.Query.FilterQueryOption.get_FilterClause()
   at Microsoft.AspNetCore.OData.Query.FilterQueryOption.ApplyTo(IQueryable query, ODataQuerySettings querySettings)
   at Program.<<Main>$>g__CreateQuery|0_0[TModel](ODataQueryContext oDataContext, String rule)
   at Program.<Main>$(String[] args)

The simplest set of steps to reproduce the issue. If possible, reference a commit that demonstrates the issue.

Data Model

[DataContract]
public class MyModel : Dictionary<string, object>
{
    [Key]
    [DataMember(Name = "id")]
    [JsonPropertyName("id")]
    public int Id { get; set; }

    [DataMember(Name = "knownString")]
    [JsonPropertyName("knownString")]
    public string KnownString { get; set; } = null!;

    [Required]
    [DataMember(Name = "knownInt")]
    [JsonPropertyName("knownInt")]
    public int KnownInt { get; set; }

    [DataMember(Name = "knownComplexTypeArray")]
    [JsonPropertyName("knownComplexTypeArray")]
    public KnownComplexType[] KnownComplexTypeArray { get; set; } = null!;

    [JsonExtensionData]
    public Dictionary<string, object> OpenProperties => this;
}

[DataContract]
public class KnownComplexType
{
    [DataMember(Name = "fileName")]
    public string FileName { get; set; } = null!;
}

EDM (CSDL) Model It's auto generated, but can supply if needed

Request/Response see queries above

Expected behavior The queries are compiled and can later be translated by the e.g. Cosmos implementation

Screenshots

Additional context See the repro repo

Tvde1 avatar Oct 15 '24 15:10 Tvde1