/// <summary> /// Accept a V3 request URI and return a V4 request URI. V4 request URI retains base path. /// </summary> /// <param name="requestUri">V3 Request URI</param> /// <returns>V4 Request URI</returns> public Uri TranslateUri(Uri requestUri) { // Use UriTranslator to walk v3 segments, translating each to v4 and returning. ODataPath v3path = new ODataUriParser(this.v3Model, this.serviceRoot).ParsePath(requestUri); UriSegmentTranslator uriTranslator = new UriSegmentTranslator(this.v4Model); Microsoft.OData.UriParser.ODataPath v4path = new Microsoft.OData.UriParser.ODataPath(v3path.WalkWith(uriTranslator)); // Parse query options for translation NameValueCollection requestQuery = HttpUtility.ParseQueryString(requestUri.Query); // Create a v4 ODataUri and utilized ODataUriExtensions methods to build v4 URI ODataUri v4Uri = new ODataUri() { Path = v4path, Filter = ParseFilterFromQueryOrNull(requestQuery, v4path, v3path) }; Uri v4RelativeUri = ODataUriExtensions.BuildUri(v4Uri, ODataUrlKeyDelimiter.Parentheses); Uri v4FullUri = new Uri(serviceRoot, v4RelativeUri); // Translated query only contains translated filter clause // We need to move everything from v3 query that does not require translation to v4 query NameValueCollection translatedQuery = HttpUtility.ParseQueryString(v4FullUri.Query); // Copy values from requestQuery to new translated query. Iterate with multiple loops // because NameValueCollections also support multiple values to one key foreach (string k in requestQuery) { foreach (string v in requestQuery.GetValues(k)) { string key = k.Trim(); if (key == "$inlinecount") { translatedQuery["$count"] = ParseInlineCountFromQuery(v.Trim()); } else if (key != "$filter") { translatedQuery[k] = v; } } } UriBuilder builder = new UriBuilder(serviceRoot.Scheme, serviceRoot.Host, serviceRoot.Port, v4FullUri.AbsolutePath); // NameValueCollection ToString is overriden to produce a URL-encoded string, decode it to maintain consistency builder.Query = WebUtility.UrlDecode(translatedQuery.ToString()); return(builder.Uri); }
// new, ok private ODataQueryContext GetQueryContext(Type rootType, Type entityType) { MakeModel(rootType); //var entitySet = _model.FindDeclaredEntitySet(rootType.Name); var segment = new Microsoft.OData.UriParser.PathTemplateSegment($"~/"); // {rootType.Name} var path = new ODataPath(segment); var uriParseODataPath = new Microsoft.OData.UriParser.ODataPath(segment); var queryContext = new ODataQueryContext(_model, entityType, path) { DefaultQuerySettings = { EnableCount = true, EnableExpand = true, EnableFilter = true, EnableOrderBy = true, EnableSelect = true, //MaxTop = 100, }, }; return(queryContext); }
// If filter clause is found in query, translate from v3 filter clause to v4 clause private Microsoft.OData.UriParser.FilterClause ParseFilterFromQueryOrNull(NameValueCollection query, Microsoft.OData.UriParser.ODataPath pathSegments, ODataPath v3Segments) { Microsoft.OData.UriParser.FilterClause v4FilterClause = null; // The MSDN specification advises checking if NameValueCollection contains key by using indexing // https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized.namevaluecollection.item?redirectedfrom=MSDN&view=netframework-4.8#System_Collections_Specialized_NameValueCollection_Item_System_String_ if (query["$filter"] != null) { // Parse filter clause in v3 EntitySetSegment entitySegment = v3Segments.Reverse().FirstOrDefault(segment => segment is EntitySetSegment) as EntitySetSegment; Data.Edm.IEdmEntityType entityType = entitySegment.EntitySet.ElementType; FilterClause v3FilterClause = ODataUriParser.ParseFilter(query["$filter"], v3Model, entityType); // Translate node and range variable into v4 format QueryNodeTranslator queryTranslator = new QueryNodeTranslator(v4Model); Microsoft.OData.UriParser.SingleValueNode v4Node = (Microsoft.OData.UriParser.SingleValueNode)v3FilterClause.Expression.Accept(queryTranslator); Microsoft.OData.UriParser.RangeVariable v4Var = queryTranslator.TranslateRangeVariable(v3FilterClause.RangeVariable); v4FilterClause = new Microsoft.OData.UriParser.FilterClause(v4Node, v4Var); } return(v4FilterClause); }