private async Task <ContainerProperties> ReadCollectionAsync( string collectionLink, IDocumentClientRetryPolicy retryPolicyInstance, ITrace trace, IClientSideRequestStatistics clientSideRequestStatistics, CancellationToken cancellationToken) { using (ITrace childTrace = trace.StartChild("Read Collection", TraceComponent.Transport, TraceLevel.Info)) { cancellationToken.ThrowIfCancellationRequested(); RequestNameValueCollection headers = new RequestNameValueCollection(); using (DocumentServiceRequest request = DocumentServiceRequest.Create( OperationType.Read, ResourceType.Collection, collectionLink, AuthorizationTokenType.PrimaryMasterKey, headers)) { headers.XDate = Rfc1123DateTimeCache.UtcNow(); request.RequestContext.ClientRequestStatistics = clientSideRequestStatistics ?? new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, trace.Summary); if (clientSideRequestStatistics == null) { childTrace.AddDatum( "Client Side Request Stats", request.RequestContext.ClientRequestStatistics); } string authorizationToken = await this.tokenProvider.GetUserAuthorizationTokenAsync( request.ResourceAddress, PathsHelper.GetResourcePath(request.ResourceType), HttpConstants.HttpMethods.Get, request.Headers, AuthorizationTokenType.PrimaryMasterKey, childTrace); headers.Authorization = authorizationToken; using (new ActivityScope(Guid.NewGuid())) { retryPolicyInstance?.OnBeforeSendRequest(request); try { using (DocumentServiceResponse response = await this.storeModel.ProcessMessageAsync(request)) { return(CosmosResource.FromStream <ContainerProperties>(response)); } } catch (DocumentClientException ex) { childTrace.AddDatum("Exception Message", ex.Message); throw; } } } } }
private async Task <DocumentServiceResponse> GetMasterAddressesViaGatewayAsync( DocumentServiceRequest request, ResourceType resourceType, string resourceAddress, string entryUrl, bool forceRefresh, bool useMasterCollectionResolver) { INameValueCollection addressQuery = new RequestNameValueCollection { { HttpConstants.QueryStrings.Url, HttpUtility.UrlEncode(entryUrl) } }; INameValueCollection headers = new RequestNameValueCollection(); if (forceRefresh) { headers.Set(HttpConstants.HttpHeaders.ForceRefresh, bool.TrueString); } if (useMasterCollectionResolver) { headers.Set(HttpConstants.HttpHeaders.UseMasterCollectionResolver, bool.TrueString); } if (request.ForceCollectionRoutingMapRefresh) { headers.Set(HttpConstants.HttpHeaders.ForceCollectionRoutingMapRefresh, bool.TrueString); } addressQuery.Add(HttpConstants.QueryStrings.Filter, this.protocolFilter); string resourceTypeToSign = PathsHelper.GetResourcePath(resourceType); headers.Set(HttpConstants.HttpHeaders.XDate, Rfc1123DateTimeCache.UtcNow()); using (ITrace trace = Trace.GetRootTrace(nameof(GetMasterAddressesViaGatewayAsync), TraceComponent.Authorization, TraceLevel.Info)) { string token = await this.tokenProvider.GetUserAuthorizationTokenAsync( resourceAddress, resourceTypeToSign, HttpConstants.HttpMethods.Get, headers, AuthorizationTokenType.PrimaryMasterKey, trace); headers.Set(HttpConstants.HttpHeaders.Authorization, token); Uri targetEndpoint = UrlUtility.SetQuery(this.addressEndpoint, UrlUtility.CreateQuery(addressQuery)); string identifier = GatewayAddressCache.LogAddressResolutionStart(request, targetEndpoint); using (HttpResponseMessage httpResponseMessage = await this.httpClient.GetAsync( uri: targetEndpoint, additionalHeaders: headers, resourceType: resourceType, timeoutPolicy: HttpTimeoutPolicyControlPlaneRetriableHotPath.Instance, clientSideRequestStatistics: request.RequestContext?.ClientRequestStatistics, cancellationToken: default))
private async Task <DocumentServiceResponse> GetFeedResponseAsync(string resourceLink, ResourceType resourceType, IDocumentClientRetryPolicy retryPolicyInstance, CancellationToken cancellationToken) { RequestNameValueCollection headers = new RequestNameValueCollection(); if (this.feedOptions.MaxItemCount.HasValue) { headers.PageSize = this.feedOptions.MaxItemCount.ToString(); } if (this.feedOptions.SessionToken != null) { headers.SessionToken = this.feedOptions.SessionToken; } if (resourceType.IsPartitioned() && this.feedOptions.PartitionKeyRangeId == null && this.feedOptions.PartitionKey == null) { throw new ForbiddenException(RMResources.PartitionKeyRangeIdOrPartitionKeyMustBeSpecified); } // On REST level, change feed is using IfNoneMatch/ETag instead of continuation. if (this.nextIfNoneMatch != null) { headers.IfNoneMatch = this.nextIfNoneMatch; } if (this.ifModifiedSince != null) { headers.IfModifiedSince = this.ifModifiedSince; } headers.Set(HttpConstants.HttpHeaders.A_IM, HttpConstants.A_IMHeaderValues.IncrementalFeed); if (this.feedOptions.PartitionKey != null) { PartitionKeyInternal partitionKey = this.feedOptions.PartitionKey.InternalKey; headers.PartitionKey = partitionKey.ToJsonString(); } if (this.feedOptions.IncludeTentativeWrites) { headers.IncludeTentativeWrites = bool.TrueString; } using (DocumentServiceRequest request = this.client.CreateDocumentServiceRequest( OperationType.ReadFeed, resourceLink, resourceType, headers)) { if (resourceType.IsPartitioned() && this.feedOptions.PartitionKeyRangeId != null) { request.RouteTo(new PartitionKeyRangeIdentity(this.feedOptions.PartitionKeyRangeId)); } return(await this.client.ReadFeedAsync(request, retryPolicyInstance, cancellationToken)); } }
private void ValidateLazyHeadersAreNotCreated(CosmosMessageHeadersInternal internalHeaders) { RequestNameValueCollection storeRequestHeaders = (RequestNameValueCollection)internalHeaders.INameValueCollection; FieldInfo lazyHeaders = typeof(Documents.Collections.RequestNameValueCollection).GetField("lazyNotCommonHeaders", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); Lazy <Dictionary <string, string> > lazyNotCommonHeaders = (Lazy <Dictionary <string, string> >)lazyHeaders.GetValue(storeRequestHeaders); // Use the if instead of Assert.IsFalse to avoid creating the dictionary in the error message if (lazyNotCommonHeaders.IsValueCreated) { Assert.Fail($"The lazy dictionary should not be created. Please add the following headers to the {nameof(Documents.Collections.RequestNameValueCollection)}: {JsonConvert.SerializeObject(lazyNotCommonHeaders.Value)}"); } }
public void StoreRequestHeadersPointRead() { _ = new RequestNameValueCollection { { HttpConstants.HttpHeaders.Authorization, AuthValue }, { HttpConstants.HttpHeaders.XDate, Date }, { HttpConstants.HttpHeaders.ClientRetryAttemptCount, Retry }, { HttpConstants.HttpHeaders.PartitionKey, Partitionkey }, { HttpConstants.HttpHeaders.RemainingTimeInMsOnClientRequest, Remaining }, { HttpConstants.HttpHeaders.TransportRequestID, Transport }, { WFConstants.BackendHeaders.CollectionRid, Rid } }; }
[Ignore] /* TODO: There is a TODO in PartitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken that it's refering to some pending deployment */ public void TestExtractPartitionKeyRangeFromHeaders() { Func <string, INameValueCollection> getHeadersWithContinuation = (string continuationToken) => { INameValueCollection headers = new RequestNameValueCollection(); headers[HttpConstants.HttpHeaders.Continuation] = continuationToken; return(headers); }; using (Stream stream = new MemoryStream(Properties.Resources.BaselineTest_PartitionRoutingHelper_ExtractPartitionKeyRangeFromHeaders)) { using (StreamReader reader = new StreamReader(stream)) { TestSet <ExtractPartitionKeyRangeFromHeadersTestData> testSet = JsonConvert.DeserializeObject <TestSet <ExtractPartitionKeyRangeFromHeadersTestData> >(reader.ReadToEnd()); foreach (ExtractPartitionKeyRangeFromHeadersTestData testData in testSet.Postive) { INameValueCollection headers = getHeadersWithContinuation(testData.CompositeContinuationToken); List <CompositeContinuationToken> suppliedTokens; Range <string> range = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken(headers, out suppliedTokens); if (suppliedTokens != null) { Assert.AreEqual(testData.ContinuationToken, headers[HttpConstants.HttpHeaders.Continuation]); Assert.AreEqual(JsonConvert.SerializeObject(testData.PartitionKeyRange), JsonConvert.SerializeObject(range)); } else { Assert.IsTrue(testData.ContinuationToken == headers[HttpConstants.HttpHeaders.Continuation] || testData.ContinuationToken == null); } } foreach (ExtractPartitionKeyRangeFromHeadersTestData testData in testSet.Negative) { INameValueCollection headers = getHeadersWithContinuation(testData.CompositeContinuationToken); try { List <CompositeContinuationToken> suppliedTokens; Range <string> rangeOrId = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken(headers, out suppliedTokens); Assert.Fail("Expect BadRequestException"); } catch (BadRequestException) { } } } } }
public async Task TestGetPartitionRoutingInfo() { using (Stream stream = new MemoryStream(Properties.Resources.BaselineTest_PartitionRoutingHelper_GetPartitionRoutingInfo)) { using (StreamReader reader = new StreamReader(stream)) { GetPartitionRoutingInfoTestData testData = JsonConvert.DeserializeObject <GetPartitionRoutingInfoTestData>(reader.ReadToEnd()); CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( testData.RoutingMap.Select(range => Tuple.Create(range, (ServiceIdentity)null)), string.Empty); foreach (GetPartitionRoutingInfoTestCase testCase in testData.TestCases) { List <string> actualPartitionKeyRangeIds = new List <string>(); Range <string> startRange = Range <string> .GetEmptyRange(PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey); for (Range <string> currentRange = startRange; currentRange != null;) { RoutingMapProvider routingMapProvider = new RoutingMapProvider(routingMap); PartitionRoutingHelper.ResolvedRangeInfo resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRangeAsync(testCase.ProvidedRanges, routingMapProvider, string.Empty, currentRange, null, NoOpTrace.Singleton); actualPartitionKeyRangeIds.Add(resolvedRangeInfo.ResolvedRange.Id); INameValueCollection headers = new RequestNameValueCollection(); await this.partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync(headers, testCase.ProvidedRanges, routingMapProvider, string.Empty, resolvedRangeInfo, NoOpTrace.Singleton); List <CompositeContinuationToken> suppliedTokens; Range <string> nextRange = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken(headers, out suppliedTokens); currentRange = nextRange.IsEmpty ? null : nextRange; } Assert.AreEqual(string.Join(", ", testCase.RoutingRangeIds), string.Join(", ", actualPartitionKeyRangeIds)); } } } }
private async Task <AccountProperties> GetDatabaseAccountAsync(Uri serviceEndpoint) { INameValueCollection headers = new RequestNameValueCollection(); await this.cosmosAuthorization.AddAuthorizationHeaderAsync( headersCollection : headers, serviceEndpoint, HttpConstants.HttpMethods.Get, AuthorizationTokenType.PrimaryMasterKey); using (ITrace trace = Trace.GetRootTrace("Account Read", TraceComponent.Transport, TraceLevel.Info)) { IClientSideRequestStatistics stats = new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, trace.Summary); try { using (HttpResponseMessage responseMessage = await this.httpClient.GetAsync( uri: serviceEndpoint, additionalHeaders: headers, resourceType: ResourceType.DatabaseAccount, timeoutPolicy: HttpTimeoutPolicyControlPlaneRead.Instance, clientSideRequestStatistics: stats, cancellationToken: default))
public async Task AddPartitionKeyRangeToContinuationTokenOnBoundry() { List <Range <string> > providedRanges = new List <Range <string> > { new Range <string>( "A", "D", isMinInclusive: true, isMaxInclusive: false) }; //Reverse ResolvedRangeInfo currentPartitionKeyRange = new ResolvedRangeInfo(new PartitionKeyRange { Id = "0", MinInclusive = "A", MaxExclusive = "B" }, null); IReadOnlyList <PartitionKeyRange> overlappingRanges = new List <PartitionKeyRange> { new PartitionKeyRange { Id = "0", MinInclusive = "A", MaxExclusive = "B" }, }.AsReadOnly(); Mock <IRoutingMapProvider> routingMapProvider = new Mock <IRoutingMapProvider>(); routingMapProvider.Setup(m => m.TryGetOverlappingRangesAsync( It.IsAny <string>(), It.Is <Range <string> >(x => x.Min == providedRanges.Single().Min&& x.Max == providedRanges.Single().Max), It.IsAny <ITrace>(), It.Is <bool>(x => x == false) )).Returns(Task.FromResult(overlappingRanges)).Verifiable(); PartitionRoutingHelper partitionRoutingHelper = new PartitionRoutingHelper(); RequestNameValueCollection headers = new(); bool result = await partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync( headers, providedRanges, routingMapProvider.Object, CollectionId, currentPartitionKeyRange, NoOpTrace.Singleton, RntdbEnumerationDirection.Reverse ); Assert.IsTrue(result); routingMapProvider.Verify(); string expectedContinuationToken = JsonConvert.SerializeObject(new CompositeContinuationToken { Token = null, Range = overlappingRanges.First().ToRange(), }); Assert.IsNull(headers.Get(HttpConstants.HttpHeaders.Continuation)); //Forward currentPartitionKeyRange = new ResolvedRangeInfo(new PartitionKeyRange { Id = "0", MinInclusive = "A", MaxExclusive = "D" }, null); overlappingRanges = new List <PartitionKeyRange> { new PartitionKeyRange { Id = "0", MinInclusive = "A", MaxExclusive = "D" }, }.AsReadOnly(); routingMapProvider.Setup(m => m.TryGetOverlappingRangesAsync( It.IsAny <string>(), It.IsAny <Range <string> >(), It.IsAny <ITrace>(), It.IsAny <bool>() )).Returns(Task.FromResult(overlappingRanges)); headers = new RequestNameValueCollection(); result = await partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync( headers, providedRanges, routingMapProvider.Object, CollectionId, currentPartitionKeyRange, NoOpTrace.Singleton, RntdbEnumerationDirection.Forward ); Assert.IsTrue(result); routingMapProvider.Verify(m => m.TryGetOverlappingRangesAsync( It.IsAny <string>(), It.Is <Range <string> >(e => e.IsMaxInclusive), It.IsAny <ITrace>(), It.IsAny <bool>() ), Times.Never); expectedContinuationToken = JsonConvert.SerializeObject(new CompositeContinuationToken { Token = null, Range = overlappingRanges.Last().ToRange(), }); Assert.IsNull(headers.Get(HttpConstants.HttpHeaders.Continuation)); }
private async Task <CollectionRoutingMap> GetRoutingMapForCollectionAsync( string collectionRid, CollectionRoutingMap previousRoutingMap, ITrace trace, IClientSideRequestStatistics clientSideRequestStatistics) { List <PartitionKeyRange> ranges = new List <PartitionKeyRange>(); string changeFeedNextIfNoneMatch = previousRoutingMap?.ChangeFeedNextIfNoneMatch; HttpStatusCode lastStatusCode = HttpStatusCode.OK; do { INameValueCollection headers = new RequestNameValueCollection(); headers.Set(HttpConstants.HttpHeaders.PageSize, PageSizeString); headers.Set(HttpConstants.HttpHeaders.A_IM, HttpConstants.A_IMHeaderValues.IncrementalFeed); if (changeFeedNextIfNoneMatch != null) { headers.Set(HttpConstants.HttpHeaders.IfNoneMatch, changeFeedNextIfNoneMatch); } RetryOptions retryOptions = new RetryOptions(); using (DocumentServiceResponse response = await BackoffRetryUtility <DocumentServiceResponse> .ExecuteAsync( () => this.ExecutePartitionKeyRangeReadChangeFeedAsync(collectionRid, headers, trace, clientSideRequestStatistics), new ResourceThrottleRetryPolicy(retryOptions.MaxRetryAttemptsOnThrottledRequests, retryOptions.MaxRetryWaitTimeInSeconds))) { lastStatusCode = response.StatusCode; changeFeedNextIfNoneMatch = response.Headers[HttpConstants.HttpHeaders.ETag]; FeedResource <PartitionKeyRange> feedResource = response.GetResource <FeedResource <PartitionKeyRange> >(); if (feedResource != null) { ranges.AddRange(feedResource); } } }while (lastStatusCode != HttpStatusCode.NotModified); IEnumerable <Tuple <PartitionKeyRange, ServiceIdentity> > tuples = ranges.Select(range => Tuple.Create(range, (ServiceIdentity)null)); CollectionRoutingMap routingMap; if (previousRoutingMap == null) { // Splits could have happened during change feed query and we might have a mix of gone and new ranges. HashSet <string> goneRanges = new HashSet <string>(ranges.SelectMany(range => range.Parents ?? Enumerable.Empty <string>())); routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( tuples.Where(tuple => !goneRanges.Contains(tuple.Item1.Id)), string.Empty, changeFeedNextIfNoneMatch); } else { routingMap = previousRoutingMap.TryCombine(tuples, changeFeedNextIfNoneMatch); } if (routingMap == null) { // Range information either doesn't exist or is not complete. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: GetRoutingMapForCollectionAsync(collectionRid: {collectionRid}), Range information either doesn't exist or is not complete."); } trace.AddDatum($"PKRangeCache Info({DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)})", new PartitionKeyRangeCacheTraceDatum( previousContinuationToken: previousRoutingMap?.ChangeFeedNextIfNoneMatch, continuationToken: routingMap.ChangeFeedNextIfNoneMatch)); return(routingMap); }
public async Task <INameValueCollection> CreateCommonHeadersAsync(FeedOptions feedOptions) { INameValueCollection requestHeaders = new RequestNameValueCollection(); Cosmos.ConsistencyLevel defaultConsistencyLevel = (Cosmos.ConsistencyLevel) await this.Client.GetDefaultConsistencyLevelAsync(); Cosmos.ConsistencyLevel?desiredConsistencyLevel = (Cosmos.ConsistencyLevel?) await this.Client.GetDesiredConsistencyLevelAsync(); if (!string.IsNullOrEmpty(feedOptions.SessionToken) && !ReplicatedResourceClient.IsReadingFromMaster(this.ResourceTypeEnum, OperationType.ReadFeed)) { if (defaultConsistencyLevel == Cosmos.ConsistencyLevel.Session || (desiredConsistencyLevel.HasValue && desiredConsistencyLevel.Value == Cosmos.ConsistencyLevel.Session)) { // Query across partitions is not supported today. Master resources (for e.g., database) // can span across partitions, whereas server resources (viz: collection, document and attachment) // don't span across partitions. Hence, session token returned by one partition should not be used // when quering resources from another partition. // Since master resources can span across partitions, don't send session token to the backend. // As master resources are sync replicated, we should always get consistent query result for master resources, // irrespective of the chosen replica. // For server resources, which don't span partitions, specify the session token // for correct replica to be chosen for servicing the query result. requestHeaders[HttpConstants.HttpHeaders.SessionToken] = feedOptions.SessionToken; } } requestHeaders[HttpConstants.HttpHeaders.Continuation] = feedOptions.RequestContinuationToken; requestHeaders[HttpConstants.HttpHeaders.IsQuery] = bool.TrueString; // Flow the pageSize only when we are not doing client eval if (feedOptions.MaxItemCount.HasValue) { requestHeaders[HttpConstants.HttpHeaders.PageSize] = feedOptions.MaxItemCount.ToString(); } requestHeaders[HttpConstants.HttpHeaders.EnableCrossPartitionQuery] = feedOptions.EnableCrossPartitionQuery.ToString(); if (feedOptions.MaxDegreeOfParallelism != 0) { requestHeaders[HttpConstants.HttpHeaders.ParallelizeCrossPartitionQuery] = bool.TrueString; } if (this.feedOptions.EnableScanInQuery != null) { requestHeaders[HttpConstants.HttpHeaders.EnableScanInQuery] = this.feedOptions.EnableScanInQuery.ToString(); } if (this.feedOptions.EmitVerboseTracesInQuery != null) { requestHeaders[HttpConstants.HttpHeaders.EmitVerboseTracesInQuery] = this.feedOptions.EmitVerboseTracesInQuery.ToString(); } if (this.feedOptions.EnableLowPrecisionOrderBy != null) { requestHeaders[HttpConstants.HttpHeaders.EnableLowPrecisionOrderBy] = this.feedOptions.EnableLowPrecisionOrderBy.ToString(); } if (!string.IsNullOrEmpty(this.feedOptions.FilterBySchemaResourceId)) { requestHeaders[HttpConstants.HttpHeaders.FilterBySchemaResourceId] = this.feedOptions.FilterBySchemaResourceId; } if (this.feedOptions.ResponseContinuationTokenLimitInKb != null) { requestHeaders[HttpConstants.HttpHeaders.ResponseContinuationTokenLimitInKB] = this.feedOptions.ResponseContinuationTokenLimitInKb.ToString(); } if (this.feedOptions.ConsistencyLevel.HasValue) { await this.Client.EnsureValidOverwriteAsync( (Documents.ConsistencyLevel) feedOptions.ConsistencyLevel.Value, OperationType.ReadFeed, this.ResourceTypeEnum); requestHeaders.Set(HttpConstants.HttpHeaders.ConsistencyLevel, this.feedOptions.ConsistencyLevel.Value.ToString()); } else if (desiredConsistencyLevel.HasValue) { requestHeaders.Set(HttpConstants.HttpHeaders.ConsistencyLevel, desiredConsistencyLevel.Value.ToString()); } if (this.feedOptions.EnumerationDirection.HasValue) { requestHeaders.Set(HttpConstants.HttpHeaders.EnumerationDirection, this.feedOptions.EnumerationDirection.Value.ToString()); } if (this.feedOptions.ReadFeedKeyType.HasValue) { requestHeaders.Set(HttpConstants.HttpHeaders.ReadFeedKeyType, this.feedOptions.ReadFeedKeyType.Value.ToString()); } if (this.feedOptions.StartId != null) { requestHeaders.Set(HttpConstants.HttpHeaders.StartId, this.feedOptions.StartId); } if (this.feedOptions.EndId != null) { requestHeaders.Set(HttpConstants.HttpHeaders.EndId, this.feedOptions.EndId); } if (this.feedOptions.StartEpk != null) { requestHeaders.Set(HttpConstants.HttpHeaders.StartEpk, this.feedOptions.StartEpk); } if (this.feedOptions.EndEpk != null) { requestHeaders.Set(HttpConstants.HttpHeaders.EndEpk, this.feedOptions.EndEpk); } if (this.feedOptions.PopulateQueryMetrics) { requestHeaders[HttpConstants.HttpHeaders.PopulateQueryMetrics] = bool.TrueString; } if (this.feedOptions.ForceQueryScan) { requestHeaders[HttpConstants.HttpHeaders.ForceQueryScan] = bool.TrueString; } if (this.feedOptions.MergeStaticId != null) { requestHeaders.Set(HttpConstants.HttpHeaders.MergeStaticId, this.feedOptions.MergeStaticId); } if (this.feedOptions.CosmosSerializationFormatOptions != null) { requestHeaders[HttpConstants.HttpHeaders.ContentSerializationFormat] = this.feedOptions.CosmosSerializationFormatOptions.ContentSerializationFormat; } else if (this.feedOptions.ContentSerializationFormat.HasValue) { requestHeaders[HttpConstants.HttpHeaders.ContentSerializationFormat] = this.feedOptions.ContentSerializationFormat.Value.ToString(); } return(requestHeaders); }
private void AddFormattedContinuationHeaderHelper(AddFormattedContinuationToHeaderTestUnit positiveTestData, out INameValueCollection headers, out List <PartitionKeyRange> resolvedRanges, out List <CompositeContinuationToken> resolvedContinuationTokens) { Func <string, INameValueCollection> getHeadersWithContinuation = (string continuationToken) => { INameValueCollection localHeaders = new RequestNameValueCollection(); if (continuationToken != null) { localHeaders[HttpConstants.HttpHeaders.Continuation] = continuationToken; } return(localHeaders); }; resolvedRanges = positiveTestData.ResolvedRanges.Select(x => new PartitionKeyRange() { MinInclusive = x.Min, MaxExclusive = x.Max }).ToList(); resolvedContinuationTokens = new List <CompositeContinuationToken>(); CompositeContinuationToken[] initialContinuationTokens = null; if (!string.IsNullOrEmpty(positiveTestData.InputCompositeContinuationToken)) { if (positiveTestData.InputCompositeContinuationToken.Trim().StartsWith("[", StringComparison.Ordinal)) { initialContinuationTokens = JsonConvert.DeserializeObject <CompositeContinuationToken[]>(positiveTestData.InputCompositeContinuationToken); } else { initialContinuationTokens = new CompositeContinuationToken[] { JsonConvert.DeserializeObject <CompositeContinuationToken>(positiveTestData.InputCompositeContinuationToken) }; } } if (resolvedRanges.Count > 1) { CompositeContinuationToken continuationToBeCopied; if (initialContinuationTokens != null && initialContinuationTokens.Length > 0) { continuationToBeCopied = (CompositeContinuationToken)initialContinuationTokens[0].ShallowCopy(); } else { continuationToBeCopied = new CompositeContinuationToken(); continuationToBeCopied.Token = string.Empty; } headers = getHeadersWithContinuation(continuationToBeCopied.Token); foreach (PartitionKeyRange pkrange in resolvedRanges) { CompositeContinuationToken token = (CompositeContinuationToken)continuationToBeCopied.ShallowCopy(); token.Range = pkrange.ToRange(); resolvedContinuationTokens.Add(token); } if (initialContinuationTokens != null) { resolvedContinuationTokens.AddRange(initialContinuationTokens.Skip(1)); } } else { headers = getHeadersWithContinuation(null); } }