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

NullReferenceException when call ODataUriParser.ParsePath() #592

Closed
shaofengzhu opened this Issue Jun 7, 2016 · 1 comment

Comments

Projects
None yet
4 participants
@shaofengzhu

shaofengzhu commented Jun 7, 2016

When there is function which returns an entity type, if the function does not specify EntitySetPath, the ODataUriParser.ParsePath() will throw NullReferenceException

Assemblies affected

OData .Net lib 6.15

Reproduce steps

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.OData.Core.UriParser;
using Microsoft.OData.Core.UriParser.Semantic;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;

namespace TestEdmODataPathParser
{
class Program
{
private const string EdmXml = @"
<Schema Namespace=""Microsoft.ExcelServices"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Range"">

<PropertyRef Name=""id"" />

<Property Name=""id"" Type=""Edm.String"" />
<Property Name=""address"" Type=""Edm.String"" />
<NavigationProperty Name=""format"" Type=""Microsoft.ExcelServices.RangeFormat"" ContainsTarget=""true"" />

<EntityType Name=""RangeFormat"">

<PropertyRef Name=""id"" />

<Property Name=""id"" Type=""Edm.String"" />
<Property Name=""horizontalAlignment"" Type=""Edm.String"" />

<EntityType Name=""Worksheet"">

<PropertyRef Name=""id"" />

<Property Name=""id"" Type=""Edm.String"" />
<Property Name=""name"" Type=""Edm.String"" />

<Function Name=""range"" IsBound=""true"" IsComposable=""true"" >
<Parameter Name=""this"" Type=""Microsoft.ExcelServices.Worksheet"" />
<Parameter Name=""address"" Type=""Edm.String"" />
<ReturnType Type=""Microsoft.ExcelServices.Range"" />

<EntityContainer Name=""EntityContainer"">
<EntitySet Name=""worksheets"" EntityType=""Microsoft.ExcelServices.Worksheet"" />
<EntitySet Name=""ranges"" EntityType=""Microsoft.ExcelServices.Range"" />


";
static void Main(string[] args)
{
IEdmModel model = GetEdmModel();
Uri uriRange = new Uri("worksheets('Sheet1')/Microsoft.ExcelServices.range(address='A1:B2')", UriKind.Relative);
Uri uriRangeFormat = new Uri("worksheets('Sheet1')/Microsoft.ExcelServices.range(address='A1:B2')/format", UriKind.Relative);
ODataUriParser parser = new ODataUriParser(model, uriRangeFormat);
ODataPath odataPath = parser.ParsePath();
foreach (ODataPathSegment segment in odataPath)
{
Console.WriteLine(segment.ToString());
if (segment.EdmType != null)
{
Console.WriteLine(segment.EdmType.FullTypeName());
}
}
}

          static IEdmModel GetEdmModel()
          {
                 IEdmModel model = null;
                 using (XmlReader reader = XmlReader.Create(new StringReader(EdmXml)))
                 {
                       IEnumerable<Microsoft.OData.Edm.Validation.EdmError> errors;
                       if (!CsdlReader.TryParse(new XmlReader[] { reader }, out model, out errors))
                       {
                              foreach (var error in errors)
                              {
                                     Console.WriteLine(error.ToString());
                              }
                       }

                       return model;
                 }
          }
   }

}

Expected result

There should be no exception

Actual result

System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreatePropertySegment(ODataPathSegment previous, IEdmProperty property, String queryPortion)
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateNextSegment(String text)
at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection1 segments) at Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection1 segments, ODataUriParserConfiguration configuration)
at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePathImplementation()
at Microsoft.OData.Core.UriParser.ODataUriParser.Initialize()
at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePath()

Additional details

It works after I created a dummy navigation property on Worksheet and specify the EntitySetPath for the function "range" to that property. The changed EDM is to add dummyEntitySet and specify EntitySetPath="this/dummyEntitySet".

   <EntityType Name=""Worksheet"">
          <Key>
                 <PropertyRef Name=""id"" />
          </Key>
          <Property Name=""id"" Type=""Edm.String"" />
          <Property Name=""name"" Type=""Edm.String"" />
          <NavigationProperty Name=""dummyEntitySet"" Type="

"Collection(Microsoft.ExcelServices.Range)"" ContainsTarget=""true"" />

<Function Name=""range"" IsBound=""true"" IsComposable=""true"" EntitySetPath =""this/dummyEntitySet"" >
<Parameter Name=""this"" Type=""Microsoft.ExcelServices.Worksheet"" />
<Parameter Name=""address"" Type=""Edm.String"" />
<ReturnType Type=""Microsoft.ExcelServices.Range"" />

shaofengzhu added a commit to shaofengzhu/odata.net that referenced this issue Jun 10, 2016

Fix for OData#592
Description of problem:
Suppose there is a function getCurrentCustomer() whose EntitySetPath is not defined, if the request URL is /getCurrentCustomer()/oneNavigationProperty, the ODataPathParser.Parse() will throw NullReferenceException as the current code requires EntitySetPath to be specified on Function that returns an enitty type.

Description of fix:
As the EdmNavigationSource is not required for NavigationPropertySegment, we do not need to require the TargetEdmNavigationSource.

LaylaLiu added a commit to LaylaLiu/odata.net that referenced this issue Jun 12, 2016

Fix for OData#592
Description of problem:
Suppose there is a function getCurrentCustomer() whose EntitySetPath is not defined, if the request URL is /getCurrentCustomer()/oneNavigationProperty, the ODataPathParser.Parse() will throw NullReferenceException as the current code requires EntitySetPath to be specified on Function that returns an enitty type.

Description of fix:
As the EdmNavigationSource is not required for NavigationPropertySegment, we do not need to require the TargetEdmNavigationSource.

@LaylaLiu LaylaLiu closed this Jun 12, 2016

chinadragon0515 added a commit to chinadragon0515/odata.net that referenced this issue Jul 12, 2016

Fix for OData#592
Description of problem:
Suppose there is a function getCurrentCustomer() whose EntitySetPath is not defined, if the request URL is /getCurrentCustomer()/oneNavigationProperty, the ODataPathParser.Parse() will throw NullReferenceException as the current code requires EntitySetPath to be specified on Function that returns an enitty type.

Description of fix:
As the EdmNavigationSource is not required for NavigationPropertySegment, we do not need to require the TargetEdmNavigationSource.
@ngRevan

This comment has been minimized.

ngRevan commented Nov 25, 2016

I am currently using the NuGet Package 6.15.0 of Microsoft.OData.Core.

I have looked at the tests for a composite key reference as I have a similar use case.
I have noticed that on the fourth navigation element in the Url, the ODataUriParser throws a NullReferenceException.

This seems to be fixed in the source code and in the Version 7.0.0 of the NuGet package but not in the Version 6.15.0.

Below is my source code.

       var model = new EdmModel();

        var customer = new EdmEntityType("Test", "Customer", null, false, true);
        var customerId = customer.AddStructuralProperty("id", EdmPrimitiveTypeKind.String, false);
        customer.AddKeys(customerId);
        model.AddElement(customer);

        var order = new EdmEntityType("Test", "Order", null, false, true);
        var orderCustomerId = order.AddStructuralProperty("customerId", EdmPrimitiveTypeKind.String, true);
        var orderOrderId = order.AddStructuralProperty("orderId", EdmPrimitiveTypeKind.String, true);
        order.AddKeys(orderCustomerId, orderOrderId);
        model.AddElement(order);

        var customerOrders = customer.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo
        {
            ContainsTarget = false,
            Name = "orders",
            Target = order,
            TargetMultiplicity = EdmMultiplicity.Many,
            DependentProperties = new[] { customerId },
            PrincipalProperties = new[] { orderCustomerId }
        });


        var item = new EdmEntityType("Test", "Item", null, false, true);
        var itemCustomerId = item.AddStructuralProperty("customerId", EdmPrimitiveTypeKind.String);
        var itemOrderId = item.AddStructuralProperty("orderId", EdmPrimitiveTypeKind.String);
        var itemItemId = item.AddStructuralProperty("id", EdmPrimitiveTypeKind.String, true);
        item.AddKeys(itemCustomerId, itemOrderId, itemItemId);
        model.AddElement(item);

        var orderItems = order.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo
        {
            ContainsTarget = false,
            Target = item,
            TargetMultiplicity = EdmMultiplicity.Many,
            Name = "items",
            DependentProperties = new[] { orderOrderId, orderCustomerId },
            PrincipalProperties = new[] { itemOrderId, itemCustomerId }
        });

        var child = new EdmEntityType("Test", "Child", null, false, true);
        var childCustomerId = item.AddStructuralProperty("customerId", EdmPrimitiveTypeKind.String);
        var childOrderId = item.AddStructuralProperty("orderId", EdmPrimitiveTypeKind.String);
        var childItemId = item.AddStructuralProperty("itemId", EdmPrimitiveTypeKind.String);
        var childChildId = item.AddStructuralProperty("id", EdmPrimitiveTypeKind.String);
        child.AddKeys(childCustomerId, childOrderId, childItemId, childChildId);
        model.AddElement(child);

        item.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo
        {
            ContainsTarget = false,
            Target = child,
            TargetMultiplicity = EdmMultiplicity.Many,
            Name = "children",
            DependentProperties = new[] { itemItemId, itemOrderId, itemCustomerId },
            PrincipalProperties = new[] { childItemId, childOrderId, childCustomerId }
        });

        var container = new EdmEntityContainer("Test", "Container");
        var customers = container.AddEntitySet("customers", customer);
        var orders = container.AddEntitySet("orders", order);
        var items = container.AddEntitySet("items", item);
        var children = container.AddEntitySet("children", child);
        model.AddElement(container);

        // Works
        //var fullUrl = "http://host/customers('customerId')/orders('orderId')/items('itemId')";

        // Fails
        var fullUrl = "http://host/customers('customerId')/orders('orderId')/items('itemId')/children";

        var parser = new ODataUriParser(model, new Uri("http://host"), new Uri(fullUrl));

        var path = parser.ParsePath().ToList();

@AlanWong-MS AlanWong-MS added P4 and removed P4 labels May 30, 2017

chuanboz pushed a commit to chuanboz/odata.net that referenced this issue Oct 4, 2018

Fix //github.com/OData/issues/592
    Description of problem:
    Suppose there is a function getCurrentCustomer() whose EntitySetPath is not defined, if the request URL is /getCurrentCustomer()/oneNavigationProperty, the ODataPathParser.Parse() will throw NullReferenceException as the current code requires EntitySetPath to be specified on Function that returns an enitty type.

    Description of fix:
    As the EdmNavigationSource is not required for NavigationPropertySegment, we do not need to require the TargetEdmNavigationSource.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment