/// <summary> /// Translate the parameter alias, convert node, returned entity set into OData path segment. /// </summary> /// <param name="model">The EDM model</param> /// <param name="path">The odata path segments</param> /// <param name="parameterAliasNodes">The parameter alias</param> /// <returns>The translated odata path segments.</returns> public static IEnumerable <ODataPathSegment> Translate(IEdmModel model, Semantic.ODataPath path, IDictionary <string, SingleValueNode> parameterAliasNodes) { if (model == null) { throw Error.ArgumentNull("model"); } if (path == null) { throw Error.ArgumentNull("path"); } var translator = new ODataPathSegmentTranslator(model, parameterAliasNodes); return(path.WalkWith(translator)); }
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 }); }
private static ODataPath Parse( IEdmModel model, string serviceRoot, string odataPath, ODataUriResolverSetttings resolverSettings, bool enableUriTemplateParsing) { ODataUriParser uriParser; Uri serviceRootUri = null; Uri fullUri = null; // TODO: Replace this type. //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")*/ "$id")); } } } ODataPath webAPIPath = ODataPathSegmentTranslator.TranslateODLPathToWebAPIPath( path, model, unresolvedPathSegment, id, enableUriTemplateParsing, uriParser.ParameterAliasNodes); CheckNavigableProperty(webAPIPath, model); return(webAPIPath); }