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); }
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}"); }
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); }); }
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); }
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); }
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()); }
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); }
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()); }
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); }
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); }
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); }
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); }
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); } }
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()); }
private ODataPath CreatePathFromUri(Uri requestUri) { var parser = new ODataUriParser(GetModel(), _serviceRoot, requestUri); return(new ODataPath(parser.ParsePath())); }
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); }
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())); }
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())); }
public static ODataPath ParsePath(IEdmModel edmModel, Uri serviceRoot, Uri uri) { var uriParser = new ODataUriParser(edmModel, serviceRoot, uri, ServiceProviderImpl.Instance); return(uriParser.ParsePath()); }
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)); } }
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())); }
/// <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)); }
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 }); }