/// <summary> /// Converts a list of CosmosElements into a memory stream. /// </summary> /// <param name="stream">The memory stream response for the query REST response Azure Cosmos</param> /// <param name="resourceType">The resource type</param> /// <param name="cosmosSerializationOptions">The custom serialization options. This allows custom serialization types like BSON, JSON, or other formats</param> /// <returns>An array of CosmosElements parsed from the response body.</returns> public static CosmosArray ParseElementsFromRestStream( Stream stream, ResourceType resourceType, CosmosSerializationFormatOptions cosmosSerializationOptions) { if (!(stream is MemoryStream memoryStream)) { memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); } if (!memoryStream.CanRead) { throw new InvalidDataException("Stream can not be read"); } // Parse out the document from the REST response like this: // { // "_rid": "qHVdAImeKAQ=", // "Documents": [{ // "id": "03230", // "_rid": "qHVdAImeKAQBAAAAAAAAAA==", // "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/", // "_etag": "\"410000b0-0000-0000-0000-597916b00000\"", // "_attachments": "attachments\/", // "_ts": 1501107886 // }], // "_count": 1 // } // You want to create a CosmosElement for each document in "Documents". ReadOnlyMemory <byte> content; if (memoryStream.TryGetBuffer(out ArraySegment <byte> buffer)) { content = buffer; } else { content = memoryStream.ToArray(); } IJsonNavigator jsonNavigator; if (cosmosSerializationOptions != null) { // Use the users custom navigator jsonNavigator = cosmosSerializationOptions.CreateCustomNavigatorCallback(content); if (jsonNavigator == null) { throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator."); } } else { jsonNavigator = JsonNavigator.Create(content); } string resourceName = resourceType switch { ResourceType.Collection => "DocumentCollections", _ => resourceType.ToResourceTypeString() + "s", }; if (!jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), resourceName, out ObjectProperty objectProperty)) { throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}"); } if (!(CosmosElement.Dispatch( jsonNavigator, objectProperty.ValueNode) is CosmosArray cosmosArray)) { throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}"); } return(cosmosArray); }
private DocumentFeedResponse <CosmosElement> GetFeedResponse( DocumentServiceRequest documentServiceRequest, DocumentServiceResponse documentServiceResponse) { // Execute the callback an each element of the page // For example just could get a response like this // { // "_rid": "qHVdAImeKAQ=", // "Documents": [{ // "id": "03230", // "_rid": "qHVdAImeKAQBAAAAAAAAAA==", // "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/", // "_etag": "\"410000b0-0000-0000-0000-597916b00000\"", // "_attachments": "attachments\/", // "_ts": 1501107886 // }], // "_count": 1 // } // And you should execute the callback on each document in "Documents". MemoryStream memoryStream = new MemoryStream(); documentServiceResponse.ResponseBody.CopyTo(memoryStream); long responseLengthBytes = memoryStream.Length; ReadOnlyMemory <byte> content; if (memoryStream.TryGetBuffer(out ArraySegment <byte> buffer)) { content = buffer; } else { content = memoryStream.ToArray(); } IJsonNavigator jsonNavigator = null; // Use the users custom navigator first. If it returns null back try the // internal navigator. if (this.feedOptions.CosmosSerializationFormatOptions != null) { jsonNavigator = this.feedOptions.CosmosSerializationFormatOptions.CreateCustomNavigatorCallback(content); if (jsonNavigator == null) { throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator."); } } else { jsonNavigator = JsonNavigator.Create(content); } string resourceName = this.GetRootNodeName(documentServiceRequest.ResourceType); if (!jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), resourceName, out ObjectProperty objectProperty)) { throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}"); } IJsonNavigatorNode cosmosElements = objectProperty.ValueNode; if (!(CosmosElement.Dispatch( jsonNavigator, cosmosElements) is CosmosArray cosmosArray)) { throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}"); } int itemCount = cosmosArray.Count; return(new DocumentFeedResponse <CosmosElement>( cosmosArray, itemCount, documentServiceResponse.Headers, documentServiceResponse.RequestStats, responseLengthBytes)); }
/// <summary> /// Converts a list of CosmosElements into a memory stream. /// </summary> /// <param name="memoryStream">The memory stream response for the query REST response Azure Cosmos</param> /// <param name="resourceType">The resource type</param> /// <param name="cosmosSerializationOptions">The custom serialization options. This allows custom serialization types like BSON, JSON, or other formats</param> /// <returns>An array of CosmosElements parsed from the response body.</returns> private static CosmosArray ParseElementsFromRestStream( MemoryStream memoryStream, ResourceType resourceType, CosmosSerializationFormatOptions cosmosSerializationOptions) { if (!memoryStream.CanRead) { throw new InvalidDataException("Stream can not be read"); } // Parse out the document from the REST response this: // { // "_rid": "qHVdAImeKAQ=", // "Documents": [{ // "id": "03230", // "_rid": "qHVdAImeKAQBAAAAAAAAAA==", // "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/", // "_etag": "\"410000b0-0000-0000-0000-597916b00000\"", // "_attachments": "attachments\/", // "_ts": 1501107886 // }], // "_count": 1 // } // You want to create a CosmosElement for each document in "Documents". ReadOnlyMemory <byte> content; if (memoryStream.TryGetBuffer(out ArraySegment <byte> buffer)) { content = buffer; } else { content = memoryStream.ToArray(); } IJsonNavigator jsonNavigator; if (cosmosSerializationOptions != null) { // Use the users custom navigator jsonNavigator = cosmosSerializationOptions.CreateCustomNavigatorCallback(content); if (jsonNavigator == null) { throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator."); } } else { jsonNavigator = JsonNavigator.Create(content); } string resourceName = resourceType switch { ResourceType.Collection => "DocumentCollections", _ => resourceType.ToResourceTypeString() + "s", }; CosmosArray documents; if ((jsonNavigator.SerializationFormat == JsonSerializationFormat.Binary) && jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), "stringDictionary", out ObjectProperty stringDictionaryProperty)) { // Payload is string dictionary encode so we have to decode using the string dictionary. IJsonNavigatorNode stringDictionaryNode = stringDictionaryProperty.ValueNode; JsonStringDictionary jsonStringDictionary = JsonStringDictionary.CreateFromStringArray( jsonNavigator .GetArrayItems(stringDictionaryNode) .Select(item => jsonNavigator.GetStringValue(item)) .ToList()); if (!jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), resourceName, out ObjectProperty resourceProperty)) { throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}"); } IJsonNavigatorNode resources = resourceProperty.ValueNode; if (!jsonNavigator.TryGetBufferedBinaryValue(resources, out ReadOnlyMemory <byte> resourceBinary)) { resourceBinary = jsonNavigator.GetBinaryValue(resources); } IJsonNavigator navigatorWithStringDictionary = JsonNavigator.Create(resourceBinary, jsonStringDictionary); if (!(CosmosElement.Dispatch( navigatorWithStringDictionary, navigatorWithStringDictionary.GetRootNode()) is CosmosArray cosmosArray)) { throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}"); } documents = cosmosArray; } else { // Payload is not string dictionary encoded so we can just do for the documents as is. if (!jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), resourceName, out ObjectProperty objectProperty)) { throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}"); } if (!(CosmosElement.Dispatch( jsonNavigator, objectProperty.ValueNode) is CosmosArray cosmosArray)) { throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}"); } documents = cosmosArray; } return(documents); }
private QueryResponse GetCosmosElementResponse( QueryRequestOptions requestOptions, ResourceType resourceType, CosmosResponseMessage cosmosResponseMessage) { using (cosmosResponseMessage) { if (!cosmosResponseMessage.IsSuccessStatusCode) { return(QueryResponse.CreateFailure( CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders(cosmosResponseMessage.Headers), cosmosResponseMessage.StatusCode, cosmosResponseMessage.RequestMessage, cosmosResponseMessage.ErrorMessage, cosmosResponseMessage.Error)); } // Execute the callback an each element of the page // For example just could get a response like this // { // "_rid": "qHVdAImeKAQ=", // "Documents": [{ // "id": "03230", // "_rid": "qHVdAImeKAQBAAAAAAAAAA==", // "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/", // "_etag": "\"410000b0-0000-0000-0000-597916b00000\"", // "_attachments": "attachments\/", // "_ts": 1501107886 // }], // "_count": 1 // } // And you should execute the callback on each document in "Documents". MemoryStream memoryStream = new MemoryStream(); cosmosResponseMessage.Content.CopyTo(memoryStream); long responseLengthBytes = memoryStream.Length; byte[] content = memoryStream.ToArray(); IJsonNavigator jsonNavigator = null; // Use the users custom navigator if (requestOptions.CosmosSerializationOptions != null) { jsonNavigator = requestOptions.CosmosSerializationOptions.CreateCustomNavigatorCallback(content); if (jsonNavigator == null) { throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator."); } } else { jsonNavigator = JsonNavigator.Create(content); } string resourceName = this.GetRootNodeName(resourceType); if (!jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), resourceName, out ObjectProperty objectProperty)) { throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}"); } IJsonNavigatorNode cosmosElements = objectProperty.ValueNode; if (!(CosmosElement.Dispatch( jsonNavigator, cosmosElements) is CosmosArray cosmosArray)) { throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}"); } int itemCount = cosmosArray.Count; return(QueryResponse.CreateSuccess( result: cosmosArray, count: itemCount, responseHeaders: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders(cosmosResponseMessage.Headers), responseLengthBytes: responseLengthBytes)); } }
private static void VerifyNavigator( string input, bool performExtraChecks = true) { CultureInfo defaultCultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture; CultureInfo[] cultureInfoList = new CultureInfo[] { defaultCultureInfo, System.Globalization.CultureInfo.GetCultureInfo("fr-FR") }; try { foreach (CultureInfo cultureInfo in cultureInfoList) { System.Threading.Thread.CurrentThread.CurrentCulture = cultureInfo; IJsonReader jsonReader = JsonReader.Create(Encoding.UTF8.GetBytes(input)); JsonToken[] tokensFromReader = JsonNavigatorTests.GetTokensWithReader(jsonReader); // Text IJsonNavigator textNavigator = JsonNavigator.Create(Encoding.UTF8.GetBytes(input)); // Binary byte[] binaryInput = JsonTestUtils.ConvertTextToBinary(input); IJsonNavigator binaryNavigator = JsonNavigator.Create(binaryInput); // Test binary + user string encoding JsonStringDictionary jsonStringDictionary = new JsonStringDictionary(capacity: 4096); byte[] binaryWithUserStringEncodingInput = JsonTestUtils.ConvertTextToBinary(input, jsonStringDictionary); if (jsonStringDictionary.TryGetStringAtIndex(index: 0, value: out _)) { Assert.IsFalse(binaryWithUserStringEncodingInput.SequenceEqual(binaryInput), "Binary should be different with user string encoding"); } IJsonNavigator binaryNavigatorWithUserStringEncoding = JsonNavigator.Create(binaryInput, jsonStringDictionary); // Test foreach (IJsonNavigator jsonNavigator in new IJsonNavigator[] { textNavigator, binaryNavigator, binaryNavigatorWithUserStringEncoding }) { IJsonNavigatorNode rootNode = jsonNavigator.GetRootNode(); JsonToken[] tokensFromNavigator = JsonNavigatorTests.GetTokensFromNode(rootNode, jsonNavigator, performExtraChecks); Assert.IsTrue(tokensFromNavigator.SequenceEqual(tokensFromReader)); // Test materialize JToken materializedToken = CosmosElement.Dispatch(jsonNavigator, rootNode).Materialize <JToken>(); try { if (materializedToken.ToString() != JToken.Parse(input).ToString()) { throw new MaterilizationFailedToMatchException(); } } catch (Newtonsoft.Json.JsonReaderException) { // If the input is extended type we ignore this check. } } } } finally { System.Threading.Thread.CurrentThread.CurrentCulture = defaultCultureInfo; } }
private static void VerifyNavigator( string input, bool performExtraChecks = true) { CultureInfo defaultCultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture; CultureInfo[] cultureInfoList = new CultureInfo[] { defaultCultureInfo, System.Globalization.CultureInfo.GetCultureInfo("fr-FR") }; try { foreach (CultureInfo cultureInfo in cultureInfoList) { System.Threading.Thread.CurrentThread.CurrentCulture = cultureInfo; IJsonReader jsonReader = JsonReader.Create(Encoding.UTF8.GetBytes(input)); JsonToken[] tokensFromReader = JsonNavigatorTests.GetTokensWithReader(jsonReader); // Text IJsonNavigator textNavigator = JsonNavigator.Create(Encoding.UTF8.GetBytes(input)); // Binary byte[] binaryInput = JsonTestUtils.ConvertTextToBinary(input); IJsonNavigator binaryNavigator = JsonNavigator.Create(binaryInput); // Test foreach (IJsonNavigator jsonNavigator in new IJsonNavigator[] { textNavigator, binaryNavigator }) { IJsonNavigatorNode rootNode = jsonNavigator.GetRootNode(); JsonToken[] tokensFromNavigator = JsonNavigatorTests.GetTokensFromNode(rootNode, jsonNavigator, performExtraChecks); Assert.AreEqual(tokensFromNavigator.Length, tokensFromReader.Length); IEnumerable <(JsonToken, JsonToken)> zippedTokens = tokensFromNavigator.Zip(tokensFromReader, (first, second) => (first, second)); foreach ((JsonToken tokenFromNavigator, JsonToken tokenFromReader) in zippedTokens) { if (!tokenFromNavigator.Equals(tokenFromReader)) { Assert.Fail(); } } // Test materialize JToken materializedToken = CosmosElement.Dispatch(jsonNavigator, rootNode).Materialize <JToken>(); try { if (materializedToken.ToString() != JToken.Parse(input).ToString()) { throw new MaterilizationFailedToMatchException(); } } catch (Newtonsoft.Json.JsonReaderException) { // If the input is extended type we ignore this check. } } } } finally { System.Threading.Thread.CurrentThread.CurrentCulture = defaultCultureInfo; } }