public void ParsePathTemplateSegmentWithTemplateParser()
        {
            var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People({1})/{some}", UriKind.Relative))
            {
                EnableUriTemplateParsing = true
            };

            var paths = uriParser.ParsePath().ToList();

            var keySegment = Assert.IsType <KeySegment>(paths[1]);
            KeyValuePair <string, object> keypair = keySegment.Keys.Single();

            Assert.Equal("ID", keypair.Key);
            var edmTypeReference = ((IEdmEntityType)keySegment.EdmType).DeclaredKey.Single().Type;

            keypair.Value.ShouldBeUriTemplateExpression("{1}", edmTypeReference);

            var templateSegment = Assert.IsType <PathTemplateSegment>(paths[2]);

            Assert.Equal("{some}", templateSegment.LiteralText);
        }
Beispiel #2
0
        public void ParsePathTemplateSegmentWithTemplateParser()
        {
            var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People({1})/{some}", UriKind.Relative))
            {
                EnableUriTemplateParsing = true
            };

            var paths = uriParser.ParsePath().ToList();

            var keySegment = paths[1].As <KeySegment>();
            KeyValuePair <string, object> keypair = keySegment.Keys.Single();

            keypair.Key.Should().Be("ID");
            keypair.Value.As <UriTemplateExpression>().ShouldBeEquivalentTo(new UriTemplateExpression {
                LiteralText = "{1}", ExpectedType = keySegment.EdmType.As <IEdmEntityType>().DeclaredKey.Single().Type
            });

            var templateSegment = paths[2].As <PathTemplateSegment>();

            templateSegment.LiteralText.Should().Be("{some}");
        }
Beispiel #3
0
        protected override ODataMessageWriterSettings GetWriterSettings()
        {
            ODataMessageWriterSettings settings = new ODataMessageWriterSettings
            {
                AutoComputePayloadMetadataInJson = true,
                PayloadBaseUri = this.ServiceRootUri
            };

            ODataUriParser uriParser = new ODataUriParser(this.DataSource.Model, ServiceConstants.ServiceBaseUri, originalUri);

            settings.ODataUri = new ODataUri()
            {
                RequestUri      = originalUri,
                ServiceRoot     = this.ServiceRootUri,
                Path            = uriParser.ParsePath(),
                SelectAndExpand = uriParser.ParseSelectAndExpand()
            };

            // TODO: howang read the encoding from request.
            settings.SetContentType(string.IsNullOrEmpty(this.QueryContext.FormatOption) ? this.RequestAcceptHeader : this.QueryContext.FormatOption, Encoding.UTF8.WebName);
            return(settings);
        }
        public void KeyLookupBinderErrorTest()
        {
            IEdmModel model = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            var testCases = new[] {
                new {
                    CaseUri         = new Uri("Customers(ID=1,ID=2)", UriKind.Relative),
                    ExpectedMessage = "A key property 'ID' was found twice in a key lookup. Each key property can be specified just once in a key lookup."
                },
                new {
                    CaseUri         = new Uri("Customers(Name='Bob')", UriKind.Relative),
                    ExpectedMessage = "Property 'Name' is not declared on type 'TestNS.Customer' or is not a key property. Only key properties can be used in key lookups."
                },
                new {
                    CaseUri         = new Uri("Customers(UndeclaredProperty='Bob')", UriKind.Relative),
                    ExpectedMessage = "Property 'UndeclaredProperty' is not declared on type 'TestNS.Customer' or is not a key property. Only key properties can be used in key lookups.",
                },
                new {
                    CaseUri         = new Uri("MultiKeys(KeyA='Bob')", UriKind.Relative),
                    ExpectedMessage = "A key lookup on type 'TestNS.MultiKey' didn't specify values for all key properties. All key properties must be specified in a key lookup.",
                },
                new {
                    CaseUri         = new Uri("MultiKeys('Bob')", UriKind.Relative),
                    ExpectedMessage = "An unnamed key value was used in a key lookup on a type 'TestNS.MultiKey' which has more than one key property. Unnamed key value can only be used on a type with one key property.",
                },
                new {
                    CaseUri         = new Uri("Customers(ID='Bob')", UriKind.Relative),
                    ExpectedMessage = "Expression of type 'Edm.String' cannot be converted to type 'Edm.Int32'.",
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases, (testCase) =>
            {
                var parser    = new ODataUriParser(model, testCase.CaseUri);
                Action action = () => parser.ParsePath();
                action.ShouldThrow <ODataException>().WithMessage(testCase.ExpectedMessage);
            });
        }
Beispiel #5
0
        public void GetODataPayloadSerializer_ReturnsRawValueSerializer_ForDollarCountRequests(string uri, Type elementType)
        {
            // Arrange
            IEdmModel model = _edmDollarCountModel;

            Type           type   = typeof(ICollection <>).MakeGenericType(elementType);
            ODataUriParser parser = new ODataUriParser(model, new Uri(uri, UriKind.Relative));
            var            path   = parser.ParsePath();

            var request = RequestFactory.Create(model);

            request.ODataFeature().Path = path;

            // Act
            var serializer = _serializerProvider.GetODataPayloadSerializer(type, request);

            // Assert
            Assert.NotNull(serializer);
            var rawValueSerializer = Assert.IsType <ODataRawValueSerializer>(serializer);

            Assert.Equal(ODataPayloadKind.Value, rawValueSerializer.ODataPayloadKind);
        }
Beispiel #6
0
    static void Main(string[] args)
    {
        var builder = new ODataConventionModelBuilder();

        builder.Namespace = "api";
        builder.EntityType <File>();
        var function = builder.EntityType <Path>().Function("getFileByName");

        function.Parameter <string>("name");
        //function.ReturnsFromEntitySet<File>("Files");
        function.ReturnsEntityViaEntitySetPath <File>("bindingParameter/File");
        function.IsComposable = true;
        builder.EntitySet <Path>("Paths");
        builder.EntitySet <Version>("Versions");
        var model = builder.GetEdmModel();

        string path   = "Paths('1')/api.getFileByName(name='sd')/Versions('s')";
        var    parser = new ODataUriParser(model, new Uri(path, UriKind.Relative));
        var    pa     = parser.ParsePath();

        Console.WriteLine(pa);
    }
Beispiel #7
0
        public void ParseWithAllQueryOptionsWithoutAlias()
        {
            ODataUriParser parser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://www.odata.com/OData/"), new Uri("http://www.odata.com/OData/Dogs?$select=Color, MyPeople&$expand=MyPeople&$filter=startswith(Color, 'Blue')&$orderby=Color asc"));

            parser.ParsePath().FirstSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetDogsSet());
            var myDogSelectedItems = parser.ParseSelectAndExpand().SelectedItems.ToList();

            myDogSelectedItems.Count.Should().Be(3);
            myDogSelectedItems[1].ShouldBePathSelectionItem(new ODataPath(new PropertySegment(HardCodedTestModel.GetDogColorProp())));
            var myPeopleExpansionSelectionItem = myDogSelectedItems[0].ShouldBeSelectedItemOfType <ExpandedNavigationSelectItem>().And;

            myPeopleExpansionSelectionItem.PathToNavigationProperty.Single().ShouldBeNavigationPropertySegment(HardCodedTestModel.GetDogMyPeopleNavProp());
            myPeopleExpansionSelectionItem.SelectAndExpand.SelectedItems.Should().BeEmpty();
            var startsWithArgs = parser.ParseFilter().Expression.ShouldBeSingleValueFunctionCallQueryNode("startswith").And.Parameters.ToList();

            startsWithArgs[0].ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetDogColorProp());
            startsWithArgs[1].ShouldBeConstantQueryNode("Blue");
            var orderby = parser.ParseOrderBy();

            orderby.Direction.Should().Be(OrderByDirection.Ascending);
            orderby.Expression.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetDogColorProp());
        }
Beispiel #8
0
        public static TKey GetKeyFromUri <TKey>(HttpRequest request, Uri uri)
        {
            // if (uri == null)
            // {
            //     throw new ArgumentNullException("uri");
            // }
            // var urlHelper = request.GetUrlHelper();// ?? new UrlHelper(request);
            // var pathHandler = (IODataPathHandler)request.GetRequestContainer().GetService(typeof(IODataPathHandler));
            // string serviceRoot = urlHelper.CreateODataLink(
            //     "request.ODataProperties().RouteName",
            //     pathHandler, new List<ODataPathSegment>());
            // var odataPath = pathHandler.Parse(serviceRoot, uri.LocalPath, request.GetRequestContainer());
            // var keySegment = odataPath.Segments.OfType<KeySegment>().FirstOrDefault();
            // if (keySegment == null)
            // {
            //     throw new InvalidOperationException("The link does not contain a key.");
            // }
            // var value = keySegment.Keys.FirstOrDefault().Value;
            // return (TKey)value;
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            // Calculate root Uri
            var rootPath = uri.AbsoluteUri.Substring(0, uri.AbsoluteUri.LastIndexOf('/') + 1);

            var odataUriParser = new ODataUriParser(SingletonEdmModel.GetEdmModel(), new Uri(rootPath), uri);
            var odataPath      = odataUriParser.ParsePath();
            var keySegment     = odataPath.LastSegment as KeySegment;

            if (keySegment == null)
            {
                throw new InvalidOperationException("The link does not contain a key.");
            }

            return((TKey)keySegment.Keys.First().Value);
        }
Beispiel #9
0
        protected virtual ODataMessageWriterSettings GetWriterSettings()
        {
            ODataMessageWriterSettings settings = new ODataMessageWriterSettings
            {
                BaseUri  = this.ServiceRootUri,
                ODataUri = new ODataUri()
                {
                    RequestUri      = this.RequestUri,
                    ServiceRoot     = this.ServiceRootUri,
                    Path            = this.QueryContext.QueryPath,
                    SelectAndExpand = this.QueryContext.QuerySelectExpandClause,
                },
                Validations      = ~ValidationKinds.ThrowOnUndeclaredPropertyForNonOpenType,
                IgnoreNullValues = false
                                   // EnableIndentation = true
            };

            // TODO: howang why here?
            if (this.QueryContext != null)
            {
                if (this.QueryContext.CanonicalUri == null)
                {
                    settings.ODataUri.RequestUri = this.QueryContext.QueryUri;
                    settings.ODataUri.Path       = this.QueryContext.QueryPath;
                }
                else
                {
                    settings.ODataUri.RequestUri = this.QueryContext.CanonicalUri;
                    ODataUriParser uriParser = new ODataUriParser(this.DataSource.Model, ServiceConstants.ServiceBaseUri, this.QueryContext.CanonicalUri);
                    settings.ODataUri.Path = uriParser.ParsePath();
                }
            }

            // TODO: howang read the encoding from request.
            settings.SetContentType(string.IsNullOrEmpty(this.QueryContext.FormatOption) ? this.RequestAcceptHeader : this.QueryContext.FormatOption, Encoding.UTF8.WebName);

            return(settings);
        }
        public void EmptyValueQueryOptionShouldWork()
        {
            var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, new Uri(FullUri, "?$filter=&$select=&$expand=&$orderby=&$top=&$skip=&$count=&$search=&$unknow=&$unknowvalue"));
            var path      = uriParser.ParsePath();

            path.Should().HaveCount(1);
            path.LastSegment.ShouldBeEntitySetSegment(HardCodedTestModel.GetPeopleSet());
            uriParser.ParseFilter().Should().BeNull();
            var results = uriParser.ParseSelectAndExpand();

            results.AllSelected.Should().BeTrue();
            results.SelectedItems.Should().HaveCount(0);
            uriParser.ParseOrderBy().Should().BeNull();
            Action action = () => uriParser.ParseTop();

            action.ShouldThrow <ODataException>().WithMessage(Strings.SyntacticTree_InvalidTopQueryOptionValue(""));
            action = () => uriParser.ParseSkip();
            action.ShouldThrow <ODataException>().WithMessage(Strings.SyntacticTree_InvalidSkipQueryOptionValue(""));
            action = () => uriParser.ParseCount();
            action.ShouldThrow <ODataException>().WithMessage(Strings.ODataUriParser_InvalidCount(""));
            action = () => uriParser.ParseSearch();
            action.ShouldThrow <ODataException>().WithMessage(Strings.UriQueryExpressionParser_ExpressionExpected(0, ""));
        }
        private ODataPath ParseDynamicPathSegmentFunc_ReturnNavAndSegment(Uri fullUri)
        {
            var container = ContainerBuilderHelper.BuildContainer(builder => builder.AddService <UriPathParser, SingleSegmentUriPathParser>(ServiceLifetime.Scoped));
            var uriParser = new ODataUriParser(oneDriveModel, ServiceRoot, fullUri, container);

            uriParser.ParseDynamicPathSegmentFunc = (previous, identifier, parenthesisExpression) =>
            {
                switch (identifier)
                {
                case "customizedDrive":
                    return(new List <ODataPathSegment>
                    {
                        new SingletonSegment(driveSingleton)
                        {
                            Identifier = identifier
                        }
                    });

                case "root:/OData/Doc/OData Client for .NET.pptx:":
                    var navPropSeg = new NavigationPropertySegment(itemsNavProp, containedItemsNav);
                    var keySegment = new KeySegment(navPropSeg, new Dictionary <string, object>()
                    {
                        { "id", "test" }
                    }, itemType, containedItemsNav);
                    return(new List <ODataPathSegment>
                    {
                        navPropSeg,
                        keySegment
                    });

                default:
                    throw new Exception("Not supported Type");
                }
            };

            return(uriParser.ParsePath());
        }
Beispiel #12
0
        private static ODataResource ReadEntityFromUrl(IEdmModel edmModel, Uri baseUri, Uri requestUrl, out IEdmEntitySet entitySet)
        {
            var       parser     = new ODataUriParser(edmModel, baseUri, requestUrl);
            ODataPath path       = parser.ParsePath();
            var       keySegment = (KeySegment)path.LastSegment;

            entitySet = (IEdmEntitySet)keySegment.NavigationSource;

            var properties = new List <ODataProperty>();

            foreach (var key in keySegment.Keys)
            {
                properties.Add(new ODataProperty()
                {
                    Name = key.Key, Value = key.Value
                });
            }
            var entry = new ODataResource()
            {
                Properties = properties
            };

            return(entry);
        }
Beispiel #13
0
        public void TestStringAsEnumInFunctionParameterOfCollectionType()
        {
            // This works even StringAsEnum not enabled.
            var uriParser = new ODataUriParser(
                Model,
                ServiceRoot,
                new Uri("http://host/GetMixedColorImport(co=['Blue', null])"))
            {
                Resolver = new ODataUriResolver()
            };

            var path = uriParser.ParsePath();
            var node = path.LastSegment
                       .ShouldBeOperationImportSegment(GetMixedColor)
                       .And.ShouldHaveParameterCount(1)
                       .And.Parameters.Single().Value.As <ConstantNode>();
            var values = node.Value.ShouldBeODataCollectionValue().And;

            var items = values.Items.Cast <object>().ToList();

            items.Count.Should().Be(2);
            items[0].ShouldBeODataEnumValue("TestNS.Color", "Blue");
            items[1].Should().BeNull();
        }
        private ODataUriParser ParseDynamicPathSegmentFunc_ReturnDynamicPathSegment(Uri fullUri, out ODataPath odataPath)
        {
            var container = ContainerBuilderHelper.BuildContainer(builder => builder.AddService <UriPathParser, SingleSegmentUriPathParser>(ServiceLifetime.Scoped));

            var uriParser = new ODataUriParser(oneDriveModel, ServiceRoot, fullUri, container);

            uriParser.ParseDynamicPathSegmentFunc = (previous, identifier, parenthesisExpression) =>
            {
                switch (identifier)
                {
                case "root:/OData/Doc/OData Client for .NET.pptx":
                case "root:/OData/Doc/OData Client for .NET.pptx:":
                    return(new List <ODataPathSegment> {
                        new DynamicPathSegment(identifier, itemType, containedItemsNav, true)
                    });

                default:
                    throw new Exception("Not supported Type");
                }
            };
            odataPath = uriParser.ParsePath();

            return(uriParser);
        }
Beispiel #15
0
        public void ErrorKeyTemplateInputShouldThrow()
        {
            var errorCases = new[]
            {
                new { Input = "{", Error = Strings.ExpressionLexer_UnbalancedBracketExpression },
                new { Input = "}", Error = Strings.ExpressionLexer_InvalidCharacter("}", 1, "(})") },
                new { Input = "{}1", Error = Strings.UriQueryExpressionParser_CloseParenOrCommaExpected(3, "({}1)") }, //Strings.BadRequest_KeyCountMismatch("Fully.Qualified.Namespace.Person")},
                new { Input = "}{", Error = Strings.ExpressionLexer_InvalidCharacter("}", 1, "(}{)") },
                new { Input = "{{}", Error = Strings.ExpressionLexer_UnbalancedBracketExpression },                    // Thrown by ODataPathParser::TryBindKeyFromParentheses
                new { Input = "{}}", Error = Strings.ExpressionLexer_InvalidCharacter("}", 3, "({}})") },
                new { Input = "{#}", Error = Strings.RequestUriProcessor_SyntaxError },
            };

            foreach (var errorCase in errorCases)
            {
                var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("http://host"), new Uri("http://host/People(" + errorCase.Input + ")"))
                {
                    EnableUriTemplateParsing = true
                };

                Action action = () => uriParser.ParsePath();
                action.ShouldThrow <ODataException>().WithMessage(errorCase.Error);
            }
        }
        public void ParseDynamicPathSegmentFunc_ReturnDynamicPathSegment_FollowedByDynamicPathSegmentsAndProp()
        {
            var container = ContainerBuilderHelper.BuildContainer(builder => builder.AddService <UriPathParser, MultipleSegmentUriPathParser>(ServiceLifetime.Scoped));
            Uri fullUri   = new Uri("https://serviceRoot/drives('b!3195njZm9ECS0rQfW5QyZ0iJh-jL7uZGn60CTehSbIwT3VAIax8sRKiyg_aD0HNV')/root:/OData/Doc/OData%20Client%20for%20.NET.pptx:/folder/childCount");
            var uriParser = new ODataUriParser(oneDriveModel, ServiceRoot, fullUri, container);

            var childCountProp = folderType.FindProperty("childCount");

            uriParser.ParseDynamicPathSegmentFunc = (previous, identifier, parenthesisExpression) =>
            {
                switch (identifier)
                {
                case "root":
                case "OData":
                case "Doc":
                case "OData Client for .NET.pptx":
                    return(new List <ODataPathSegment> {
                        new DynamicPathSegment(identifier, itemType, containedItemsNav, true)
                    });

                default:
                    throw new Exception("Not supported Type");
                }
            };

            var parseDynamicPathSegmentFuncClone = uriParser.ParseDynamicPathSegmentFunc;

            Assert.Equal(uriParser.ParseDynamicPathSegmentFunc, parseDynamicPathSegmentFuncClone);
            var path = uriParser.ParsePath();

            path.ElementAt(2).ShouldBeDynamicPathSegment("root");
            path.ElementAt(3).ShouldBeDynamicPathSegment("OData");
            path.ElementAt(4).ShouldBeDynamicPathSegment("Doc");
            path.ElementAt(5).ShouldBeDynamicPathSegment("OData Client for .NET.pptx");
            path.LastSegment.ShouldBePropertySegment(childCountProp);
        }
Beispiel #17
0
        protected virtual ODataMessageWriterSettings GetWriterSettings()
        {
            ODataMessageWriterSettings settings = new ODataMessageWriterSettings
            {
                AutoComputePayloadMetadataInJson = true,
                PayloadBaseUri = this.ServiceRootUri,
                ODataUri       = new ODataUri()
                {
                    RequestUri      = this.RequestUri,
                    ServiceRoot     = this.ServiceRootUri,
                    Path            = this.QueryContext.QueryPath,
                    SelectAndExpand = this.QueryContext.QuerySelectExpandClause,
                }
            };

            // TODO: howang why here?
            if (this.QueryContext != null)
            {
                if (this.QueryContext.CanonicalUri == null)
                {
                    settings.ODataUri.RequestUri = this.QueryContext.QueryUri;
                    settings.ODataUri.Path       = this.QueryContext.QueryPath;
                }
                else
                {
                    settings.ODataUri.RequestUri = this.QueryContext.CanonicalUri;
                    ODataUriParser uriParser = new ODataUriParser(this.DataSource.Model, ServiceConstants.ServiceBaseUri, this.QueryContext.CanonicalUri);
                    settings.ODataUri.Path = uriParser.ParsePath();
                }
            }

            // TODO: howang read the encoding from request.
            settings.SetContentType(string.IsNullOrEmpty(this.QueryContext.FormatOption) ? this.RequestAcceptHeader : this.QueryContext.FormatOption, Encoding.UTF8.WebName);

            return(settings);
        }
Beispiel #18
0
        public void ErrorParameterTemplateInputShouldThrow()
        {
            var errorCases = new[]
            {
                new { Input = "{", Error = Strings.ExpressionLexer_UnbalancedBracketExpression },
                new { Input = "}", Error = Strings.ExpressionLexer_InvalidCharacter("}", 6, "onCat=}") },
                new { Input = "{}1", Error = Strings.ExpressionLexer_SyntaxError(9, "onCat={}1") },
                new { Input = "}{", Error = Strings.ExpressionLexer_InvalidCharacter("}", 6, "onCat=}{") },
                new { Input = "{{}", Error = Strings.ExpressionLexer_UnbalancedBracketExpression }, // Thrown by ODataPathParser::TryBindingParametersAndMatchingOperation
                new { Input = "{}}", Error = Strings.ExpressionLexer_InvalidCharacter("}", 8, "onCat={}}") },
                new { Input = "{#}", Error = Strings.RequestUriProcessor_SyntaxError },
            };

            foreach (var errorCase in errorCases)
            {
                var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, new Uri("People(1)/Fully.Qualified.Namespace.HasHat(onCat=" + errorCase.Input + ")", UriKind.Relative))
                {
                    EnableUriTemplateParsing = true
                };

                Action action = () => uriParser.ParsePath();
                action.ShouldThrow <ODataException>().WithMessage(errorCase.Error);
            }
        }
Beispiel #19
0
        public void TryEnableNoDollarSignSystemQueryOption(string relativeUri)
        {
            // Create parser specifying optional-$-sign setting.
            var parser = new ODataUriParser(GetModel(), new Uri(relativeUri, UriKind.Relative))
            {
                EnableNoDollarQueryOptions = true
            };

            // Verify path is parsed correctly.
            Microsoft.OData.UriParser.ODataPath path = parser.ParsePath();
            Assert.NotNull(path);
            Assert.Equal(2, path.Count);

            // Verify expand & select clause is parsed correctly.
            SelectExpandClause result = parser.ParseSelectAndExpand();

            Assert.NotNull(result);
            Assert.Single(result.SelectedItems);
            ExpandedNavigationSelectItem selectItems = (result.SelectedItems.First() as ExpandedNavigationSelectItem);

            Assert.NotNull(selectItems);
            Assert.Equal("PermanentAccount", selectItems.NavigationSource.Name);
            Assert.Equal(2, selectItems.SelectAndExpand.SelectedItems.Count());
        }
Beispiel #20
0
        private ODataPath CreatePathFromUri(Uri requestUri)
        {
            var parser = new ODataUriParser(GetModel(), _serviceRoot, requestUri);

            return(new ODataPath(parser.ParsePath()));
        }
Beispiel #21
0
        private ODataPayloadKind ParseContextUriFragment(string fragment, Func <IEdmType, string, IEdmType> clientCustomTypeResolver, bool throwIfMetadataConflict, out bool isUndeclared)
        {
            bool           hasItemSelector = false;
            ODataDeltaKind kind            = ODataDeltaKind.None;

            isUndeclared = false;

            // Deal with /$entity
            if (fragment.EndsWith(ODataConstants.ContextUriFragmentItemSelector, StringComparison.Ordinal))
            {
                hasItemSelector = true;
                fragment        = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriFragmentItemSelector.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeltaResourceSet, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.ResourceSet;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeltaResourceSet.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeletedEntry, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.DeletedEntry;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeletedEntry.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeltaLink, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.Link;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeltaLink.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeletedLink, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.DeletedLink;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeletedLink.Length);
            }

            this.parseResult.DeltaKind = kind;

            // Deal with query option
            if (fragment.EndsWith(")", StringComparison.Ordinal))
            {
                int index = fragment.Length - 2;
                for (int rcount = 1; rcount > 0 && index > 0; --index)
                {
                    switch (fragment[index])
                    {
                    case '(':
                        rcount--;
                        break;

                    case ')':
                        rcount++;
                        break;
                    }
                }

                if (index == 0)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                string previous = fragment.Substring(0, index + 1);

                // Don't treat Collection(Edm.Type) as SelectExpand segment
                if (!previous.Equals("Collection"))
                {
                    string selectExpandStr = fragment.Substring(index + 2);
                    selectExpandStr = selectExpandStr.Substring(0, selectExpandStr.Length - 1);

                    // Do not treat Key as SelectExpand segment
                    if (KeyPattern.IsMatch(selectExpandStr))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_LastSegmentIsKeySegment(UriUtils.UriToString(this.parseResult.ContextUri)));
                    }

                    this.parseResult.SelectQueryOption = ExtractSelectQueryOption(selectExpandStr);
                    fragment = previous;
                }
            }

            ODataPayloadKind detectedPayloadKind = ODataPayloadKind.Unsupported;
            EdmTypeResolver  edmTypeResolver     = new EdmTypeReaderResolver(this.model, clientCustomTypeResolver);

            if (!fragment.Contains(ODataConstants.UriSegmentSeparator) && !hasItemSelector && kind == ODataDeltaKind.None)
            {
                // Service document: no fragment
                if (fragment.Length == 0)
                {
                    detectedPayloadKind = ODataPayloadKind.ServiceDocument;
                }
                else if (fragment.Equals(ODataConstants.CollectionPrefix + "(" + ODataConstants.EntityReferenceSegmentName + ")"))
                {
                    detectedPayloadKind = ODataPayloadKind.EntityReferenceLinks;
                }
                else if (fragment.Equals(ODataConstants.EntityReferenceSegmentName))
                {
                    detectedPayloadKind = ODataPayloadKind.EntityReferenceLink;
                }
                else
                {
                    var foundNavigationSource = this.model.FindDeclaredNavigationSource(fragment);

                    if (foundNavigationSource != null)
                    {
                        // Resource Set: {schema.entity-container.entity-set} or Singleton: {schema.entity-container.singleton}
                        this.parseResult.NavigationSource = foundNavigationSource;
                        this.parseResult.EdmType          = edmTypeResolver.GetElementType(foundNavigationSource);
                        detectedPayloadKind = foundNavigationSource is IEdmSingleton ? ODataPayloadKind.Resource : ODataPayloadKind.ResourceSet;
                    }
                    else
                    {
                        // Property: {schema.type} or Collection({schema.type}) where schema.type is primitive or complex.
                        detectedPayloadKind = this.ResolveType(fragment, clientCustomTypeResolver, throwIfMetadataConflict);
                        Debug.Assert(
                            this.parseResult.EdmType.TypeKind == EdmTypeKind.Primitive || this.parseResult.EdmType.TypeKind == EdmTypeKind.Enum || this.parseResult.EdmType.TypeKind == EdmTypeKind.TypeDefinition || this.parseResult.EdmType.TypeKind == EdmTypeKind.Complex || this.parseResult.EdmType.TypeKind == EdmTypeKind.Collection || this.parseResult.EdmType.TypeKind == EdmTypeKind.Entity || this.parseResult.EdmType.TypeKind == EdmTypeKind.Untyped,
                            "The first context URI segment must be a set or a non-entity type.");
                    }
                }
            }
            else
            {
                Debug.Assert(this.parseResult.MetadataDocumentUri.IsAbsoluteUri, "this.parseResult.MetadataDocumentUri.IsAbsoluteUri");

                string metadataDocumentStr = UriUtils.UriToString(this.parseResult.MetadataDocumentUri);

                if (!metadataDocumentStr.EndsWith(ODataConstants.UriMetadataSegment, StringComparison.Ordinal))
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                Uri serviceRoot = new Uri(metadataDocumentStr.Substring(0, metadataDocumentStr.Length - ODataConstants.UriMetadataSegment.Length));

                ODataUriParser odataUriParser = new ODataUriParser(this.model, serviceRoot, new Uri(serviceRoot, fragment));

                ODataPath path;
                try
                {
                    path = odataUriParser.ParsePath();
                }
                catch (ODataException)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                if (path.Count == 0)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                this.parseResult.Path = path;

                parseResult.NavigationSource = path.NavigationSource();
                parseResult.EdmType          = path.LastSegment.EdmType;

                ODataPathSegment lastSegment = path.TrimEndingTypeSegment().LastSegment;
                if (lastSegment is EntitySetSegment || lastSegment is NavigationPropertySegment)
                {
                    if (kind != ODataDeltaKind.None)
                    {
                        detectedPayloadKind = ODataPayloadKind.Delta;
                    }
                    else
                    {
                        detectedPayloadKind = hasItemSelector ? ODataPayloadKind.Resource : ODataPayloadKind.ResourceSet;
                    }

                    if (this.parseResult.EdmType is IEdmCollectionType)
                    {
                        var collectionTypeReference = this.parseResult.EdmType.ToTypeReference().AsCollection();
                        if (collectionTypeReference != null)
                        {
                            this.parseResult.EdmType = collectionTypeReference.ElementType().Definition;
                        }
                    }
                }
                else if (lastSegment is SingletonSegment)
                {
                    detectedPayloadKind = ODataPayloadKind.Resource;
                }
                else if (path.IsIndividualProperty())
                {
                    isUndeclared        = path.IsUndeclared();
                    detectedPayloadKind = ODataPayloadKind.Property;
                    IEdmComplexType complexType = parseResult.EdmType as IEdmComplexType;
                    if (complexType != null)
                    {
                        detectedPayloadKind = ODataPayloadKind.Resource;
                    }
                    else
                    {
                        IEdmCollectionType collectionType = parseResult.EdmType as IEdmCollectionType;

                        if (collectionType != null)
                        {
                            if (collectionType.ElementType.IsComplex())
                            {
                                this.parseResult.EdmType = collectionType.ElementType.Definition;
                                detectedPayloadKind      = ODataPayloadKind.ResourceSet;
                            }
                            else
                            {
                                detectedPayloadKind = ODataPayloadKind.Collection;
                            }
                        }
                    }
                }
                else
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }
            }

            return(detectedPayloadKind);
        }
Beispiel #22
0
        public void PathFunctionWithParens()
        {
            ODataUriParser parserWithoutparens = new ODataUriParser(model, new Uri("http://www.potato.com/"), new Uri("http://www.potato.com/Orders/Microsoft.Test.Taupo.OData.WCFService.OrdersWithMoreThanTwoItems"));
            ODataUriParser parserWithparens    = new ODataUriParser(model, new Uri("http://www.potato.com/"), new Uri("http://www.potato.com/Orders/Microsoft.Test.Taupo.OData.WCFService.OrdersWithMoreThanTwoItems()"));

            Assert.AreEqual(QueryNodeToStringVisitor.ToString(parserWithoutparens.ParsePath()), QueryNodeToStringVisitor.ToString(parserWithparens.ParsePath()));
        }
Beispiel #23
0
        public void PathActionWithParens()
        {
            ODataUriParser parserWithoutparens = new ODataUriParser(model, new Uri("http://www.potato.com/"), new Uri("http://www.potato.com/Boss/Microsoft.Test.Taupo.OData.WCFService.ChangeAddress"));
            ODataUriParser parserWithparens    = new ODataUriParser(model, new Uri("http://www.potato.com/"), new Uri("http://www.potato.com/Boss/Microsoft.Test.Taupo.OData.WCFService.ChangeAddress()"));

            Assert.AreEqual(QueryNodeToStringVisitor.ToString(parserWithoutparens.ParsePath()), QueryNodeToStringVisitor.ToString(parserWithparens.ParsePath()));
        }
Beispiel #24
0
        public static ODataPath ParsePath(IEdmModel edmModel, Uri serviceRoot, Uri uri)
        {
            var uriParser = new ODataUriParser(edmModel, serviceRoot, uri, ServiceProviderImpl.Instance);

            return(uriParser.ParsePath());
        }
Beispiel #25
0
        private static ODataPath Parse(
            IEdmModel model,
            string serviceRoot,
            string odataPath,
            ODataUriResolverSetttings resolverSettings,
            bool enableUriTemplateParsing)
        {
            ODataUriParser      uriParser;
            Uri                 serviceRootUri = null;
            Uri                 fullUri        = null;
            NameValueCollection queryString    = null;

            if (enableUriTemplateParsing)
            {
                uriParser = new ODataUriParser(model, new Uri(odataPath, UriKind.Relative));
                uriParser.EnableUriTemplateParsing = true;
            }
            else
            {
                Contract.Assert(serviceRoot != null);

                serviceRootUri = new Uri(
                    serviceRoot.EndsWith("/", StringComparison.Ordinal) ?
                    serviceRoot :
                    serviceRoot + "/");

                fullUri     = new Uri(serviceRootUri, odataPath);
                queryString = fullUri.ParseQueryString();
                uriParser   = new ODataUriParser(model, serviceRootUri, fullUri);
            }

            uriParser.Resolver = resolverSettings.CreateResolver();

            Semantic.ODataPath    path;
            UnresolvedPathSegment unresolvedPathSegment = null;

            Semantic.KeySegment id = null;
            try
            {
                path = uriParser.ParsePath();
            }
            catch (ODataUnrecognizedPathException ex)
            {
                if (ex.ParsedSegments != null &&
                    ex.ParsedSegments.Count() > 0 &&
                    (ex.ParsedSegments.Last().EdmType is IEdmComplexType ||
                     ex.ParsedSegments.Last().EdmType is IEdmEntityType) &&
                    ex.CurrentSegment != ODataSegmentKinds.Count)
                {
                    if (ex.UnparsedSegments.Count() == 0)
                    {
                        path = new Semantic.ODataPath(ex.ParsedSegments);
                        unresolvedPathSegment = new UnresolvedPathSegment(ex.CurrentSegment);
                    }
                    else
                    {
                        // Throw ODataException if there is some segment following the unresolved segment.
                        throw new ODataException(Error.Format(
                                                     SRResources.InvalidPathSegment,
                                                     ex.UnparsedSegments.First(),
                                                     ex.CurrentSegment));
                    }
                }
                else
                {
                    throw;
                }
            }

            if (!enableUriTemplateParsing && path.LastSegment is Semantic.NavigationPropertyLinkSegment)
            {
                IEdmCollectionType lastSegmentEdmType = path.LastSegment.EdmType as IEdmCollectionType;

                if (lastSegmentEdmType != null)
                {
                    Semantic.EntityIdSegment entityIdSegment = null;
                    bool exceptionThrown = false;

                    try
                    {
                        entityIdSegment = uriParser.ParseEntityId();

                        if (entityIdSegment != null)
                        {
                            // Create another ODataUriParser to parse $id, which is absolute or relative.
                            ODataUriParser parser = new ODataUriParser(model, serviceRootUri, entityIdSegment.Id);
                            id = parser.ParsePath().LastSegment as Semantic.KeySegment;
                        }
                    }
                    catch (ODataException)
                    {
                        // Exception was thrown while parsing the $id.
                        // We will throw another exception about the invalid $id.
                        exceptionThrown = true;
                    }

                    if (exceptionThrown ||
                        (entityIdSegment != null &&
                         (id == null ||
                          !(id.EdmType.IsOrInheritsFrom(lastSegmentEdmType.ElementType.Definition) ||
                            lastSegmentEdmType.ElementType.Definition.IsOrInheritsFrom(id.EdmType)))))
                    {
                        throw new ODataException(Error.Format(SRResources.InvalidDollarId, queryString.Get("$id")));
                    }
                }
            }

            ODataPath webAPIPath = ODataPathSegmentTranslator.TranslateODLPathToWebAPIPath(
                path,
                model,
                unresolvedPathSegment,
                id,
                enableUriTemplateParsing,
                uriParser.ParameterAliasNodes);

            CheckNavigableProperty(webAPIPath, model);
            return(webAPIPath);
        }
        internal static ODataPath RunParsePath(string path, IEdmModel model)
        {
            ODataUriParser parser = new ODataUriParser(model, new Uri("http://gobbldgook/"), new Uri("http://gobbldygook/" + path));

            return(parser.ParsePath());
        }
        public void ParseCompositeKeyReference(TestODataUrlKeyDelimiter testODataUrlKeyDelimiter, string fullUrl)
        {
            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      = true,
                Name                = "orders",
                Target              = order,
                TargetMultiplicity  = EdmMultiplicity.Many,
                DependentProperties = new[] { customerId },
                PrincipalProperties = new[] { orderCustomerId }
            });

            var detail           = new EdmEntityType("Test", "Detail");
            var detailCustomerId = detail.AddStructuralProperty("customerId", EdmPrimitiveTypeKind.String);
            var detailOrderId    = detail.AddStructuralProperty("orderId", EdmPrimitiveTypeKind.String);

            detail.AddKeys(detailCustomerId, detailOrderId,
                           detail.AddStructuralProperty("id", EdmPrimitiveTypeKind.Int32, false));
            model.AddElement(detail);

            var detailedOrder        = new EdmEntityType("Test", "DetailedOrder", order);
            var detailedOrderDetails = detailedOrder.AddUnidirectionalNavigation(
                new EdmNavigationPropertyInfo
            {
                ContainsTarget     = true,
                Target             = detail,
                TargetMultiplicity = EdmMultiplicity.Many,
                Name = "details",
                DependentProperties = new[] { orderOrderId, orderCustomerId },
                PrincipalProperties = new[] { detailOrderId, detailCustomerId }
            });

            model.AddElement(detailedOrder);

            var container = new EdmEntityContainer("Test", "Container");
            var customers = container.AddEntitySet("customers", customer);

            model.AddElement(container);

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

            switch (testODataUrlKeyDelimiter)
            {
            case TestODataUrlKeyDelimiter.Parentheses:
                parser.UrlKeyDelimiter = ODataUrlKeyDelimiter.Parentheses;
                break;

            case TestODataUrlKeyDelimiter.Slash:
                parser.UrlKeyDelimiter = ODataUrlKeyDelimiter.Slash;
                break;

            default:
                Assert.True(false, "Unreachable code path");
                break;
            }

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

            path[0].ShouldBeEntitySetSegment(customers);
            path[1].ShouldBeKeySegment(new KeyValuePair <string, object>("id", "customerId"));
            path[2].ShouldBeNavigationPropertySegment(customerOrders);
            path[3].ShouldBeKeySegment(new KeyValuePair <string, object>("customerId", "customerId"),
                                       new KeyValuePair <string, object>("orderId", "orderId"));
            if (path.Count > 4)
            {
                // For tests with a type cast and a second-level navigation property.
                path[4].ShouldBeTypeSegment(detailedOrder);
                path[5].ShouldBeNavigationPropertySegment(detailedOrderDetails);
                path[6].ShouldBeKeySegment(new KeyValuePair <string, object>("customerId", "customerId"),
                                           new KeyValuePair <string, object>("orderId", "orderId"),
                                           new KeyValuePair <string, object>("id", 1));
            }
        }
Beispiel #28
0
        public void PathFunctionWithParens()
        {
            ODataUriParser parserWithoutparens = new ODataUriParser(model, new Uri("http://www.potato.com/"), new Uri("http://www.potato.com/SpecialOrder/Microsoft.Test.Taupo.OData.WCFService.GetOrderRate"));
            ODataUriParser parserWithparens    = new ODataUriParser(model, new Uri("http://www.potato.com/"), new Uri("http://www.potato.com/SpecialOrder/Microsoft.Test.Taupo.OData.WCFService.GetOrderRate()"));

            Assert.AreEqual(QueryNodeToStringVisitor.ToString(parserWithoutparens.ParsePath()), QueryNodeToStringVisitor.ToString(parserWithparens.ParsePath()));
        }
Beispiel #29
0
        /// <summary>
        /// Resolves the parsed URI against the data store.
        /// </summary>
        /// <param name="model">The data store model.</param>
        /// <param name="dataContext">The data access context.</param>
        /// <param name="level">The level of segment need to be translated, the default value is -1 means translate all.</param>
        /// <returns>The results of querying the data store.</returns>
        public object ResolveQuery(IODataDataSource dataSource, int level = -1)
        {
            var testExpressionVisitor = new PathSegmentToExpressionTranslator(dataSource, this, this.Model)
            {
                ActionInvokeParameters = this.ActionInvokeParameters
            };

            // build linq expression from ODataPath and execute the expression
            Expression boundExpression = Expression.Constant(null);

            int levelToTranslate = level == -1 ? this.QueryPath.Count - 1 : level;

            for (int i = 0; i <= levelToTranslate; ++i)
            {
                boundExpression = this.QueryPath.ElementAt(i).TranslateWith(testExpressionVisitor);
            }

            //Handle Action without return type
            var methodCallExpression = boundExpression as MethodCallExpression;

            if (methodCallExpression != null && methodCallExpression.Method.ReturnType == typeof(void))
            {
                Expression <Action> actionLambda = Expression.Lambda <Action>(boundExpression);

                actionLambda.Compile()();
                return(null);
            }

            if (this.QueryPath.LastSegment is NavigationPropertyLinkSegment && this.QueryEntityIdSegment != null)
            {
                // We assume the $id always finish with the keysegment, and consistence with the base path.
                ODataUriParser uriParser = new ODataUriParser(this.Model, ServiceConstants.ServiceBaseUri, this.QueryEntityIdSegment.Id);
                boundExpression = uriParser.ParsePath().LastSegment.TranslateWith(testExpressionVisitor);
            }

            // handle $filter query option
            if (this.QueryFilterClause != null)
            {
                boundExpression = boundExpression.ApplyFilter(GetElementTypeForOption(ServiceConstants.QueryOption_Filter), this.UriParser, this.QueryFilterClause);
            }

            //handle $search query option
            if (this.QuerySearchClause != null)
            {
                boundExpression = boundExpression.ApplySearch(GetElementTypeForOption(ServiceConstants.QueryOption_Search), this.UriParser, this.QuerySearchClause);
            }

            //handle $orderby query option
            if (this.QueryOrderByClause != null)
            {
                boundExpression = boundExpression.ApplyOrderBy(GetElementTypeForOption(ServiceConstants.QueryOption_OrderBy), this.UriParser, this.QueryOrderByClause);
            }

            //handle $skip query option
            if (this.SkipOption != null)
            {
                boundExpression = boundExpression.ApplySkip(GetElementTypeForOption(ServiceConstants.QueryOption_Skip), this.SkipOption.Value);
            }

            //handle $top query option
            if (this.TopOption != null)
            {
                boundExpression = boundExpression.ApplyTop(GetElementTypeForOption(ServiceConstants.QueryOption_Top), this.TopOption.Value);
            }

            boundExpression = Expression.Convert(boundExpression, typeof(object));
            Expression <Func <object> > lambda = Expression.Lambda <Func <object> >(boundExpression);

            Func <object> compiled = lambda.Compile();

            var result = default(object);

            try
            {
                result = compiled();
            }
            catch (NullReferenceException)
            {
                // Currently we assume the NRE will lead to NotFound.
                throw Utility.BuildException(HttpStatusCode.NotFound);
            }

            return(ProcessQueryResult(result));
        }
Beispiel #30
0
        private ODataPath Parse(string serviceRoot, string odataPath, IServiceProvider requestContainer, bool template)
        {
            ODataUriParser uriParser;
            Uri            serviceRootUri = null;
            Uri            fullUri        = null;
            IEdmModel      model          = requestContainer.GetRequiredService <IEdmModel>();

            if (template)
            {
                uriParser = new ODataUriParser(model, new Uri(odataPath, UriKind.Relative), requestContainer);
                uriParser.EnableUriTemplateParsing = true;
            }
            else
            {
                Contract.Assert(serviceRoot != null);

                serviceRootUri = new Uri(
                    serviceRoot.EndsWith("/", StringComparison.Ordinal)
                        ? serviceRoot
                        : serviceRoot + "/");

                // Concatenate the root and path and create a Uri. Using Uri to build a Uri from
                // a root and relative path changes the casing on .NetCore. However, odataPath may
                // be a full Uri.
                if (!Uri.TryCreate(odataPath, UriKind.Absolute, out fullUri))
                {
                    fullUri = new Uri(serviceRootUri + odataPath);
                }

                // Due to a bug in the System.Uri some relative paths are rejected if they contain
                // a ':' symbol on a position greater than 1024. This careful check should mitigate
                // this problem by encoding these characters before the path is combined with
                // service roor Uri.
                // https://github.com/dotnet/corefx/issues/29011
                if (!Uri.IsWellFormedUriString(odataPath, UriKind.RelativeOrAbsolute) &&
                    odataPath.IndexOf(':') > MaxUriSchemeName)
                {
                    var odataPathColonEncoded = odataPath.Replace(":", "%3A");
                    if (Uri.IsWellFormedUriString(odataPathColonEncoded, UriKind.Relative))
                    {
                        odataPath = odataPathColonEncoded;
                    }
                }

                fullUri   = new Uri(serviceRootUri, odataPath);
                uriParser = new ODataUriParser(model, serviceRootUri, fullUri, requestContainer);
            }

            if (UrlKeyDelimiter != null)
            {
                uriParser.UrlKeyDelimiter = UrlKeyDelimiter;
            }
            else
            {
                uriParser.UrlKeyDelimiter = ODataUrlKeyDelimiter.Slash;
            }

            ODL.ODataPath         path;
            UnresolvedPathSegment unresolvedPathSegment = null;

            ODL.KeySegment id = null;
            try
            {
                path = uriParser.ParsePath();
            }
            catch (ODataUnrecognizedPathException ex)
            {
                if (ex.ParsedSegments != null &&
                    ex.ParsedSegments.Any() &&
                    (ex.ParsedSegments.Last().EdmType is IEdmComplexType ||
                     ex.ParsedSegments.Last().EdmType is IEdmEntityType) &&
                    ex.CurrentSegment != ODataSegmentKinds.Count)
                {
                    if (!ex.UnparsedSegments.Any())
                    {
                        path = new ODL.ODataPath(ex.ParsedSegments);
                        unresolvedPathSegment = new UnresolvedPathSegment(ex.CurrentSegment);
                    }
                    else
                    {
                        // Throw ODataException if there is some segment following the unresolved segment.
                        throw new ODataException(Error.Format(
                                                     SRResources.InvalidPathSegment,
                                                     ex.UnparsedSegments.First(),
                                                     ex.CurrentSegment));
                    }
                }
                else
                {
                    throw;
                }
            }

            if (!template && path.LastSegment is ODL.NavigationPropertyLinkSegment)
            {
                IEdmCollectionType lastSegmentEdmType = path.LastSegment.EdmType as IEdmCollectionType;

                if (lastSegmentEdmType != null)
                {
                    ODL.EntityIdSegment entityIdSegment = null;
                    bool exceptionThrown = false;

                    try
                    {
                        entityIdSegment = uriParser.ParseEntityId();

                        if (entityIdSegment != null)
                        {
                            // Create another ODataUriParser to parse $id, which is absolute or relative.
                            ODataUriParser parser = new ODataUriParser(model, serviceRootUri, entityIdSegment.Id, requestContainer);
                            id = parser.ParsePath().LastSegment as ODL.KeySegment;
                        }
                    }
                    catch (ODataException)
                    {
                        // Exception was thrown while parsing the $id.
                        // We will throw another exception about the invalid $id.
                        exceptionThrown = true;
                    }

                    if (exceptionThrown ||
                        (entityIdSegment != null &&
                         (id == null ||
                          !(id.EdmType.IsOrInheritsFrom(lastSegmentEdmType.ElementType.Definition) ||
                            lastSegmentEdmType.ElementType.Definition.IsOrInheritsFrom(id.EdmType)))))
                    {
                        // System.Net.Http on NetCore does not have the Uri extension method
                        // ParseQueryString(), to avoid a platform-specific call, extract $id manually.
                        string idValue = fullUri.Query;
                        string idParam = "$id=";
                        int    start   = idValue.IndexOf(idParam, StringComparison.OrdinalIgnoreCase);
                        if (start >= 0)
                        {
                            int end = idValue.IndexOf("&", start, StringComparison.OrdinalIgnoreCase);
                            if (end >= 0)
                            {
                                idValue = idValue.Substring(start + idParam.Length, end - 1);
                            }
                            else
                            {
                                idValue = idValue.Substring(start + idParam.Length);
                            }
                        }

                        throw new ODataException(Error.Format(SRResources.InvalidDollarId, idValue));
                    }
                }
            }

            // do validation for the odata path
            path.WalkWith(new DefaultODataPathValidator(model));

            // do segment translator (for example parameter alias, key & function parameter template, etc)
            var segments =
                ODataPathSegmentTranslator.Translate(model, path, uriParser.ParameterAliasNodes).ToList();

            if (unresolvedPathSegment != null)
            {
                segments.Add(unresolvedPathSegment);
            }

            if (!template)
            {
                AppendIdForRef(segments, id);
            }

            return(new ODataPath(segments)
            {
                Path = path
            });
        }