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

NullReference exception generated when using FilterClause.ApplyTo method with open properties in the filter query #1214

Open
vibatra opened this issue Apr 16, 2024 · 2 comments
Assignees
Labels
bug Something isn't working

Comments

@vibatra
Copy link

vibatra commented Apr 16, 2024

Assemblies affected
ASP.NET Core OData 8.2.5

Describe the bug
FilterClause.ApplyTo method generates a NullReferenceException if a open/dynamic property is used in the filter query. The exception happens in QueryBinder.BindPropertyAccessExpression method.

Reproduce steps

// Get local copy of graph model metadata for generating the EDM model
var xmlReader = XmlReader.Create(new StringReader(GraphMetadataForValidation.GraphMetadata));
var EdmModel = CsdlReader.Parse(xmlReader);
// Set annotations to bind the User entity in EDM model to the User class in the SDK
EdmModel.SetAnnotationValue<ClrTypeAnnotation>(EdmModel.FindType("microsoft.graph.user"), new ClrTypeAnnotation(typeof(Graph.User)));
// Generate query option for FilterClause
IDictionary<string, string> queryOptions = new Dictionary<string, string> { { "$filter", "extension_123456_attr1 eq 'Test'"} };
ODataQueryContext ctx2 = new ODataQueryContext(EdmModel, typeof(Graph.User), new ODataPath())
{
    DefaultQueryConfigurations = { EnableFilter = true },
};
var parser = new ODataQueryOptionParser(
    EdmModel,
    ctx2.ElementType,
    ctx2.NavigationSource,
    queryOptions);
parser.Resolver = new ODataUriResolver { EnableCaseInsensitive = true };

var filterQueryOption = new FilterQueryOption("extension_123456_attr1 eq 'Test'", ctx2, parser);
var results = filterQueryOption.ApplyTo(users.AsQueryable(), new ODataQuerySettings());

Data Model
The User class in Graph SDK but it can be any othr

EDM (CSDL) Model
https://[graph.microsoft.com/v1.0/$metadata#users](https://graph.microsoft.com/v1.0/$metadata#users)

Request/Response
No request/response. We are using it as stand alone.

Expected behavior
A filtered data set is returned.

Actual behavior
A NullReference exception is thrown when the ApplyTo method is called as it is not able to bind to the dynamic/additional data container on the CLR type.

Additional context
There is no way for us inject a custom implementation of FilterBinder in the stand alone mode.

@vibatra vibatra added the bug Something isn't working label Apr 16, 2024
@corranrogue9 corranrogue9 self-assigned this Apr 16, 2024
@corranrogue9
Copy link
Contributor

We certainly shouldn't be throwing a NullReferenceException. Let me look more using your repro steps.

@vibatra
Copy link
Author

vibatra commented Apr 16, 2024

We certainly shouldn't be throwing a NullReferenceException. Let me look more using your repro steps.

Below is a version of the repro steps without depending on the SDK and Graph metadata. Result is same - NRE thrown when ApplyTo is called.

        string edmMetadata = @"
<edmx:Edmx xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"" Version=""4.0"">
<edmx:DataServices>
<Schema xmlns=""http://docs.oasis-open.org/odata/ns/edm"" Namespace=""testSpace.filterClause"">
<EntityType Name=""customer"" OpenType=""true"">
<Key>
<PropertyRef Name=""id""/>
</Key>
<Property Name=""dateTimeOffsetProperty"" Type=""Edm.DateTimeOffset""/>
<Property Name=""id"" Type=""Edm.String"" Nullable=""false""/>
<Property Name=""stringProperty"" Type=""Edm.String""/>
<Property Name=""booleanProperty"" Type=""Edm.Boolean""/>
</EntityType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>";
        // Generate model from the metadata
        var xmlReader = XmlReader.Create(new StringReader(edmMetadata));
        var EdmModel = CsdlReader.Parse(xmlReader);
        // Set annotations to bind the User entity in EDM model to the User class in the SDK
        EdmModel.SetAnnotationValue(EdmModel.FindType("testSpace.filterClause.customer"), new ClrTypeAnnotation(typeof(Customer)));
        // Generate query option for FilterClause
        IDictionary<string, string> queryOptions = new Dictionary<string, string> { { "$filter", "extension_123456_attr1 eq 'Test'" } };
        ODataQueryContext ctx2 = new ODataQueryContext(EdmModel, typeof(Customer), new ODataPath())
        {
            DefaultQueryConfigurations = { EnableFilter = true },
        };
        var parser = new ODataQueryOptionParser(
            EdmModel,
            ctx2.ElementType,
            ctx2.NavigationSource,
            queryOptions);
        parser.Resolver = new ODataUriResolver { EnableCaseInsensitive = true };

        var filterQueryOption = new FilterQueryOption("extension_123456_attr1 eq 'Test'", ctx2, parser);
        List<Customer> customers = new List<Customer>() { new Customer() { Id = "test1", StringProperty = "string", BooleanProperty = true, DateTimeOffsetProperty = DateTimeOffset.UtcNow, ExtensionData = new Dictionary<string, object>() } };
        var results = filterQueryOption.ApplyTo(customers.AsQueryable(), new ODataQuerySettings());

The CLR model -

        public class Customer
        {
            public string Id { get; set; }
            public string StringProperty { get; set; }
            public bool BooleanProperty { get; set; }
            public DateTimeOffset DateTimeOffsetProperty { get; set; }
        
            public IDictionary<string, object> ExtensionData { get; set; }
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants