/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> and verifies that it is a PrimitiveValue node of type double. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the double value read from the reader; /// throws an exception if no double value could be read.</returns> internal static async Task <double?> ReadDoubleValueAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); object value = await jsonReader.ReadPrimitiveValueAsync() .ConfigureAwait(false); double?doubleValue = value as double?; if (value == null || doubleValue != null) { return(doubleValue); } int?intValue = value as int?; if (intValue != null) { return((double)intValue); } decimal?decimalValue = value as decimal?; if (decimalValue != null) { return((double)decimalValue); } throw CreateException(Strings.JsonReaderExtensions_CannotReadValueAsDouble(value)); }
/// <summary> /// Asynchronously skips over a JSON value (primitive, object or array). /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <remarks> /// Pre-Condition: JsonNodeType.PrimitiveValue, JsonNodeType.StartArray or JsonNodeType.StartObject /// Post-Condition: JsonNodeType.PrimitiveValue, JsonNodeType.EndArray or JsonNodeType.EndObject /// </remarks> /// <returns>A task that represents the asynchronous read operation.</returns> internal static async Task SkipValueAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); int depth = 0; do { switch (jsonReader.NodeType) { case JsonNodeType.StartArray: case JsonNodeType.StartObject: depth++; break; case JsonNodeType.EndArray: case JsonNodeType.EndObject: Debug.Assert(depth > 0, "Seen too many scope ends."); depth--; break; default: Debug.Assert( jsonReader.NodeType != JsonNodeType.EndOfInput, "We should not have reached end of input, since the scopes should be well formed. Otherwise JsonReader should have failed by now."); break; } }while (await jsonReader.ReadAsync().ConfigureAwait(false) && depth > 0); if (depth > 0) { // Not all open scopes were closed: // "Invalid JSON. Unexpected end of input was found in JSON content. Not all object and array scopes were closed." throw CreateException(Strings.JsonReader_EndOfInputWithOpenScope); } }
internal static async Task <bool> TryReadNullValueAsync( #endif IJsonReaderAsync jsonReader, ODataInputContext inputContext, IEdmTypeReference expectedTypeReference, bool validateNullValue, string propertyName, bool?isDynamicProperty = null) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(inputContext != null, "inputContext != null"); if (jsonReader.NodeType == JsonNodeType.PrimitiveValue && await jsonReader.GetValueAsync().ConfigureAwait(false) == null) { await jsonReader.ReadNextAsync() .ConfigureAwait(false); // NOTE: when reading a null value we will never ask the type resolver (if present) to resolve the // type; we always fall back to the expected type. inputContext.MessageReaderSettings.Validator.ValidateNullValue( expectedTypeReference, validateNullValue, propertyName, isDynamicProperty); return(true); } return(false); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> and verifies that it is of the expected node type. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <param name="expectedNodeType">The expected <see cref="JsonNodeType"/> of the read node.</param> private static async Task ReadNextAsync(this IJsonReaderAsync jsonReader, JsonNodeType expectedNodeType) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(expectedNodeType != JsonNodeType.None, "expectedNodeType != JsonNodeType.None"); jsonReader.ValidateNodeType(expectedNodeType); await jsonReader.ReadAsync().ConfigureAwait(false); }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonBatchReader">The Json batch reader.</param> private ODataJsonLightBatchPayloadItemPropertiesCache(ODataJsonLightBatchReader jsonBatchReader) { Debug.Assert(jsonBatchReader != null, $"{nameof(jsonBatchReader)} != null"); this.jsonReader = jsonBatchReader.JsonLightInputContext.JsonReader; this.asynchronousJsonReader = jsonBatchReader.JsonLightInputContext.JsonReader; this.listener = jsonBatchReader; }
/// <summary> /// Validates that the asynchronous reader is positioned on the specified node type. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to use.</param> /// <param name="expectedNodeType">The expected node type.</param> private static void ValidateNodeType(this IJsonReaderAsync jsonReader, JsonNodeType expectedNodeType) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(expectedNodeType != JsonNodeType.None, "expectedNodeType != JsonNodeType.None"); if (jsonReader.NodeType != expectedNodeType) { throw CreateException(Strings.JsonReaderExtensions_UnexpectedNodeDetected(expectedNodeType, jsonReader.NodeType)); } }
/// <summary> /// Verifies that the current node is a property node and returns the property name. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the property name of the current property node.</returns> internal static async Task <string> GetPropertyNameAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(jsonReader.NodeType == JsonNodeType.Property, "jsonReader.NodeType == JsonNodeType.Property"); // NOTE: the JSON reader already verifies that property names are strings and not null/empty object value = await jsonReader.GetValueAsync() .ConfigureAwait(false); return((string)value); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> and verifies that it is a PrimitiveValue node. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the primitive value read from the reader.</returns> internal static async Task <object> ReadPrimitiveValueAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); object value = await jsonReader.GetValueAsync() .ConfigureAwait(false); await ReadNextAsync(jsonReader, JsonNodeType.PrimitiveValue) .ConfigureAwait(false); return(value); }
/// <summary> /// Asynchronously populates the body content the Json reader is referencing. /// Since the content-type header might not be available at this point (when "headers" attribute /// is read after the "body" attribute), if the content-type is not json the body content is /// first stored into a string which will be used to populate the stream when the content-type /// header is read later. /// </summary> /// <param name="jsonReader">The Json reader providing access to the data.</param> /// <param name="contentTypeHeader">The request's content-type header value.</param> /// <returns> /// A task that represents the asynchronous write operation. /// The value of the TResult parameter contains true if body content is written to stream; false otherwise. /// </returns> internal async Task <bool> PopulateBodyContentAsync(IJsonReaderAsync jsonReader, string contentTypeHeader) { bool isStreamPopulated = false; BatchPayloadBodyContentType?contentType = DetectBatchPayloadBodyContentType(jsonReader, contentTypeHeader); if (contentType == null) { // We don't have deterministic content-type, cache the string content. Debug.Assert(jsonReader.NodeType == JsonNodeType.PrimitiveValue, "jsonReader.NodeType == JsonNodeType.PrimitiveValue"); this.cachedBodyContent = await jsonReader.ReadStringValueAsync() .ConfigureAwait(false); Debug.Assert(isStreamPopulated == false, "isStreamPopulated == false"); } else { // We have content-type figured out and should be able to populate the stream. switch (contentType) { case BatchPayloadBodyContentType.Json: await WriteJsonContentAsync(jsonReader) .ConfigureAwait(false); break; case BatchPayloadBodyContentType.Textual: string bodyContent = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", jsonReader.ReadStringValue()); await WriteBytesAsync(Encoding.UTF8.GetBytes(bodyContent)) .ConfigureAwait(false); break; case BatchPayloadBodyContentType.Binary: // Body content is a base64url encoded string. We could have used HttpServerUtility.UrlTokenDecode(string) // directly but it would introduce new dependency of System.Web.dll. string encoded = await jsonReader.ReadStringValueAsync() .ConfigureAwait(false); await WriteBinaryContentAsync(encoded) .ConfigureAwait(false); break; default: throw new ODataException(Strings.ODataJsonLightBatchBodyContentReaderStream_UnsupportedContentTypeInHeader(contentType)); } isStreamPopulated = true; } return(isStreamPopulated); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/>, verifies that it is a Property node and returns the property name. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the property name of the property node read.</returns> internal static async Task <string> ReadPropertyNameAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); jsonReader.ValidateNodeType(JsonNodeType.Property); string propertyName = await jsonReader.GetPropertyNameAsync() .ConfigureAwait(false); await jsonReader.ReadNextAsync() .ConfigureAwait(false); return(propertyName); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> as an <see cref="ODataUntypedValue"/>. /// </summary> /// <param name="jsonReader">The reader to inspect.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the <see cref="ODataUntypedValue"/> value read from the reader.</returns> internal static async Task <ODataValue> ReadAsUntypedOrNullValueAsync(this IJsonReaderAsync jsonReader) { StringBuilder builder = new StringBuilder(); await jsonReader.SkipValueAsync(builder) .ConfigureAwait(false); Debug.Assert(builder.Length > 0, "builder.Length > 0"); return(new ODataUntypedValue() { RawValue = builder.ToString(), }); }
/// <summary> /// Asynchronously reads the next node. Use this instead of the direct call to Read since this asserts that there actually is a next node. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the node type of the node that reader is positioned on after reading.</returns> internal static async Task <JsonNodeType> ReadNextAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); #if DEBUG bool result = await jsonReader.ReadAsync() .ConfigureAwait(false); Debug.Assert(result, "JsonReader.Read returned false in an unexpected place."); #else await jsonReader.ReadAsync(); #endif return(jsonReader.NodeType); }
/// <summary> /// Try and parse spatial type from the json payload. /// </summary> /// <param name="jsonReader">The JSON reader to read from.</param> /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object /// (or the second property if the first one was odata.type).</param> /// <param name="inputContext">The input context with all the settings.</param> /// <param name="expectedValueTypeReference">Expected edm property type.</param> /// <param name="validateNullValue">true to validate null values; otherwise false.</param> /// <param name="recursionDepth">The recursion depth to start with.</param> /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param> /// <returns>An instance of the spatial type.</returns> internal static async Task <ISpatial> ReadSpatialValueAsync( IJsonReaderAsync jsonReader, bool insideJsonObjectValue, ODataInputContext inputContext, IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue, int recursionDepth, string propertyName) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(inputContext != null, "inputContext != null"); Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null"); Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types"); // Spatial value can be either null constant or a JSON object // If it's a null primitive value, report a null value. if (!insideJsonObjectValue && await TryReadNullValueAsync(jsonReader, inputContext, expectedValueTypeReference, validateNullValue, propertyName) .ConfigureAwait(false)) { return(null); } ISpatial spatialValue = null; if (insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject) { Dictionary <string, object> jsonObject = await ReadObjectValueAsync(jsonReader, insideJsonObjectValue, inputContext, recursionDepth) .ConfigureAwait(false); GeoJsonObjectFormatter jsonObjectFormatter = SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter(); if (expectedValueTypeReference.IsGeography()) { spatialValue = jsonObjectFormatter.Read <Geography>(jsonObject); } else { spatialValue = jsonObjectFormatter.Read <Geometry>(jsonObject); } } if (spatialValue == null) { throw new ODataException(ODataErrorStrings.ODataJsonReaderCoreUtils_CannotReadSpatialPropertyValue); } return(spatialValue); }
/// <summary> /// Asynchronously reads off the data of the starting Json object from the Json reader, /// and populate the data into the memory stream. /// </summary> /// <param name="reader"> The json reader pointing at the json structure whose data needs to /// be populated into an memory stream. /// </param> /// <returns>A task that represents the asynchronous write operation.</returns> private async Task WriteJsonContentAsync(IJsonReaderAsync reader) { // Reader is on the value node after the "body" property name node. IJsonWriterAsync jsonWriter = new JsonWriter( new StreamWriter(this), reader.IsIeee754Compatible); await WriteCurrentJsonObjectAsync(reader, jsonWriter) .ConfigureAwait(false); await this.FlushAsync() .ConfigureAwait(false); this.Position = 0; }
/// <summary> /// Asynchronously reads the json array from the reader. /// </summary> /// <param name="jsonReader">JsonReader instance.</param> /// <param name="inputContext">The input context with all the settings.</param> /// <param name="recursionDepth">The recursion depth to start with.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains a lit of JSON objects.</returns> /// <returns>a list of json objects.</returns> private static async Task <List <object> > ReadArrayValueAsync(IJsonReaderAsync jsonReader, ODataInputContext inputContext, int recursionDepth) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(jsonReader.NodeType == JsonNodeType.StartArray, "jsonReader.NodeType == JsonNodeType.StartArray"); Debug.Assert(inputContext != null, "inputContext != null"); ValidationUtils.IncreaseAndValidateRecursionDepth(ref recursionDepth, inputContext.MessageReaderSettings.MessageQuotas.MaxNestingDepth); List <object> items = new List <object>(); await jsonReader.ReadNextAsync() .ConfigureAwait(false); while (jsonReader.NodeType != JsonNodeType.EndArray) { switch (jsonReader.NodeType) { case JsonNodeType.PrimitiveValue: items.Add(await jsonReader.ReadPrimitiveValueAsync() .ConfigureAwait(false)); break; case JsonNodeType.StartObject: items.Add(await ReadObjectValueAsync(jsonReader, /*insideJsonObjectValue*/ false, inputContext, recursionDepth) .ConfigureAwait(false)); break; case JsonNodeType.StartArray: items.Add(await ReadArrayValueAsync(jsonReader, inputContext, recursionDepth) .ConfigureAwait(false)); break; default: Debug.Assert(false, "We should never have got here - the valid states in array are primitive value or object"); return(null); } } await jsonReader.ReadEndArrayAsync() .ConfigureAwait(false); return(items); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> and verifies that it is a PrimitiveValue node of type string. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <param name="propertyName">The name of the property for which to read the string; used in error messages only.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the string value read from the reader; /// throws an exception if no string value could be read.</returns> internal static async Task <string> ReadStringValueAsync(this IJsonReaderAsync jsonReader, string propertyName = null) { Debug.Assert(jsonReader != null, "jsonReader != null"); object value = await jsonReader.ReadPrimitiveValueAsync() .ConfigureAwait(false); string stringValue = value as string; if (value == null || stringValue != null) { return(stringValue); } if (!string.IsNullOrEmpty(propertyName)) { throw CreateException(Strings.JsonReaderExtensions_CannotReadPropertyValueAsString(value, propertyName)); } else { throw CreateException(Strings.JsonReaderExtensions_CannotReadValueAsString(value)); } }
/// <summary> /// Asynchronously reads the json object value from the jsonReader /// </summary> /// <param name="jsonReader">Json reader to read payload from the wire.</param> /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object /// (or the second property if the first one was odata.type).</param> /// <param name="inputContext">The input context with all the settings.</param> /// <param name="recursionDepth">The recursion depth to start with.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains an instance of IDictionary containing the spatial value.</returns> private static async Task <Dictionary <string, object> > ReadObjectValueAsync( IJsonReaderAsync jsonReader, bool insideJsonObjectValue, ODataInputContext inputContext, int recursionDepth) { Debug.Assert(jsonReader != null, "jsonReader != null"); Debug.Assert(insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject, "insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject"); Debug.Assert( !insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.Property || jsonReader.NodeType == JsonNodeType.EndObject, "!insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.Property || jsonReader.NodeType == JsonNodeType.EndObject"); Debug.Assert(inputContext != null, "inputContext != null"); ValidationUtils.IncreaseAndValidateRecursionDepth(ref recursionDepth, inputContext.MessageReaderSettings.MessageQuotas.MaxNestingDepth); Dictionary <string, object> jsonValue = new Dictionary <string, object>(StringComparer.Ordinal); if (!insideJsonObjectValue) { // Note that if the insideJsonObjectValue is true we will ignore the odata.type instance annotation // which might have been there. This is OK since for spatial we only need the normal properties anyway. await jsonReader.ReadNextAsync() .ConfigureAwait(false); } while (jsonReader.NodeType != JsonNodeType.EndObject) { // read the property name string propertyName = await jsonReader.ReadPropertyNameAsync() .ConfigureAwait(false); // read the property value object propertyValue; switch (jsonReader.NodeType) { case JsonNodeType.PrimitiveValue: propertyValue = await jsonReader.ReadPrimitiveValueAsync() .ConfigureAwait(false); break; case JsonNodeType.StartArray: propertyValue = await ReadArrayValueAsync(jsonReader, inputContext, recursionDepth) .ConfigureAwait(false); break; case JsonNodeType.StartObject: propertyValue = await ReadObjectValueAsync(jsonReader, /*insideJsonObjectValue*/ false, inputContext, recursionDepth) .ConfigureAwait(false); break; default: Debug.Assert(false, "We should never reach here - There should be matching end element"); return(null); } jsonValue.Add(ODataAnnotationNames.RemoveAnnotationPrefix(propertyName), propertyValue); } await jsonReader.ReadEndObjectAsync() .ConfigureAwait(false); return(jsonValue); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> as a URI and verifies that it is a PrimitiveValue node of type string. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the string value read from the reader as a URI; /// throws an exception if no string value could be read.</returns> internal static async Task <Uri> ReadUriValueAsync(this IJsonReaderAsync jsonReader) { return(UriUtils.StringToUri(await ReadStringValueAsync(jsonReader) .ConfigureAwait(false))); }
/// <summary> /// Asynchronously skips over a JSON value (primitive, object or array), and append raw string to StringBuilder. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <param name="jsonRawValueStringBuilder">The StringBuilder to receive JSON raw string.</param> /// <returns>A task that represents the asynchronous read operation.</returns> internal static async Task SkipValueAsync(this IJsonReaderAsync jsonReader, StringBuilder jsonRawValueStringBuilder) { Debug.Assert(jsonReader != null, "jsonReader != null"); using (StringWriter stringWriter = new StringWriter(jsonRawValueStringBuilder, CultureInfo.InvariantCulture)) { JsonWriter jsonWriter = new JsonWriter(stringWriter, jsonReader.IsIeee754Compatible); int depth = 0; do { switch (jsonReader.NodeType) { case JsonNodeType.PrimitiveValue: if (await jsonReader.GetValueAsync().ConfigureAwait(false) == null) { await jsonWriter.WriteValueAsync((string)null) .ConfigureAwait(false); } else { object primitiveValue = await jsonReader.GetValueAsync() .ConfigureAwait(false); await jsonWriter.WritePrimitiveValueAsync(primitiveValue) .ConfigureAwait(false); } break; case JsonNodeType.StartArray: await jsonWriter.StartArrayScopeAsync() .ConfigureAwait(false); depth++; break; case JsonNodeType.StartObject: await jsonWriter.StartObjectScopeAsync() .ConfigureAwait(false); depth++; break; case JsonNodeType.EndArray: await jsonWriter.EndArrayScopeAsync() .ConfigureAwait(false); Debug.Assert(depth > 0, "Seen too many scope ends."); depth--; break; case JsonNodeType.EndObject: await jsonWriter.EndObjectScopeAsync() .ConfigureAwait(false); Debug.Assert(depth > 0, "Seen too many scope ends."); depth--; break; case JsonNodeType.Property: string propertyName = await jsonReader.GetPropertyNameAsync() .ConfigureAwait(false); await jsonWriter.WriteNameAsync(propertyName) .ConfigureAwait(false); break; default: Debug.Assert( jsonReader.NodeType != JsonNodeType.EndOfInput, "We should not have reached end of input, since the scopes should be well formed. Otherwise JsonReader should have failed by now."); break; } }while (await jsonReader.ReadAsync().ConfigureAwait(false) && depth > 0); if (depth > 0) { // Not all open scopes were closed: // "Invalid JSON. Unexpected end of input was found in JSON content. Not all object and array scopes were closed." throw CreateException(Strings.JsonReader_EndOfInputWithOpenScope); } await jsonWriter.FlushAsync() .ConfigureAwait(false); } }
/// <summary> /// Determines if the reader is on a value node. /// </summary> /// <param name="jsonReader">The reader to inspect.</param> /// <returns>true if the reader is on PrimitiveValue, StartObject or StartArray node, false otherwise.</returns> internal static bool IsOnValueNode(this IJsonReaderAsync jsonReader) { return(IsValueNodeType(jsonReader.NodeType)); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> and verifies that it is an EndArray node. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation.</returns> internal static Task ReadEndArrayAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); return(ReadNextAsync(jsonReader, JsonNodeType.EndArray)); }
/// <summary> /// Asynchronously writes the current Json object. /// </summary> /// <param name="reader">The Json reader providing the data.</param> /// <param name="jsonWriter">The Json writer writes data into memory stream.</param> /// <returns>A task that represents the asynchronous write operation.</returns> private static async Task WriteCurrentJsonObjectAsync(IJsonReaderAsync reader, IJsonWriterAsync jsonWriter) { Stack <JsonNodeType> nodeTypes = new Stack <JsonNodeType>(); do { switch (reader.NodeType) { case JsonNodeType.PrimitiveValue: object primitiveValue; if ((primitiveValue = await reader.GetValueAsync().ConfigureAwait(false)) != null) { await jsonWriter.WritePrimitiveValueAsync(primitiveValue) .ConfigureAwait(false); } else { await jsonWriter.WriteValueAsync((string)null) .ConfigureAwait(false); } break; case JsonNodeType.Property: object propertyName = await reader.GetValueAsync() .ConfigureAwait(false); await jsonWriter.WriteNameAsync(propertyName.ToString()) .ConfigureAwait(false); break; case JsonNodeType.StartObject: nodeTypes.Push(reader.NodeType); await jsonWriter.StartObjectScopeAsync() .ConfigureAwait(false); break; case JsonNodeType.StartArray: nodeTypes.Push(reader.NodeType); await jsonWriter.StartArrayScopeAsync() .ConfigureAwait(false); break; case JsonNodeType.EndObject: Debug.Assert(nodeTypes.Peek() == JsonNodeType.StartObject); nodeTypes.Pop(); await jsonWriter.EndObjectScopeAsync() .ConfigureAwait(false); break; case JsonNodeType.EndArray: Debug.Assert(nodeTypes.Peek() == JsonNodeType.StartArray); nodeTypes.Pop(); await jsonWriter.EndArrayScopeAsync() .ConfigureAwait(false); break; default: throw new ODataException(Strings.ODataJsonLightBatchBodyContentReaderStream_UnexpectedNodeType(reader.NodeType)); } await reader.ReadNextAsync() .ConfigureAwait(false); // This can be EndOfInput, where nodeTypes should be empty. }while (nodeTypes.Count != 0); await jsonWriter.FlushAsync() .ConfigureAwait(false); }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> as an <see cref="ODataValue"/>. /// </summary> /// <param name="jsonReader">The reader to inspect.</param> /// <returns>A task that represents the asynchronous read operation. /// The value of the TResult parameter contains the <see cref="ODataValue"/> value read from the reader.</returns> internal static async Task <ODataValue> ReadODataValueAsync(this IJsonReaderAsync jsonReader) { if (jsonReader.NodeType == JsonNodeType.PrimitiveValue) { object primitiveValue = await jsonReader.ReadPrimitiveValueAsync() .ConfigureAwait(false); return(primitiveValue.ToODataValue()); } else if (jsonReader.NodeType == JsonNodeType.StartObject) { await jsonReader.ReadStartObjectAsync() .ConfigureAwait(false); ODataResourceValue resourceValue = new ODataResourceValue(); List <ODataProperty> properties = new List <ODataProperty>(); while (jsonReader.NodeType != JsonNodeType.EndObject) { ODataProperty property = new ODataProperty(); property.Name = await jsonReader.ReadPropertyNameAsync() .ConfigureAwait(false); property.Value = await jsonReader.ReadODataValueAsync() .ConfigureAwait(false); properties.Add(property); } resourceValue.Properties = properties; await jsonReader.ReadEndObjectAsync() .ConfigureAwait(false); return(resourceValue); } else if (jsonReader.NodeType == JsonNodeType.StartArray) { await jsonReader.ReadStartArrayAsync() .ConfigureAwait(false); ODataCollectionValue collectionValue = new ODataCollectionValue(); List <object> properties = new List <object>(); while (jsonReader.NodeType != JsonNodeType.EndArray) { ODataValue odataValue = await jsonReader.ReadODataValueAsync() .ConfigureAwait(false); properties.Add(odataValue); } collectionValue.Items = properties; await jsonReader.ReadEndArrayAsync() .ConfigureAwait(false); return(collectionValue); } else { return(await jsonReader.ReadAsUntypedOrNullValueAsync() .ConfigureAwait(false)); } }
/// <summary> /// Wrapper method with validation to asynchronously scan the JSON object for known properties. /// </summary> /// <returns>A task that represents the asynchronous read operation.</returns> private async Task ScanJsonPropertiesAsync() { Debug.Assert(this.asynchronousJsonReader != null, $"{nameof(this.asynchronousJsonReader)} != null"); Debug.Assert(this.jsonProperties == null, $"{nameof(this.jsonProperties)} == null"); this.jsonProperties = new Dictionary <string, object>(); string contentTypeHeader = null; ODataJsonLightBatchBodyContentReaderStream bodyContentStream = null; try { // Request object start. await this.asynchronousJsonReader.ReadStartObjectAsync() .ConfigureAwait(false); while (this.asynchronousJsonReader.NodeType != JsonNodeType.EndObject) { // Convert to upper case to support case-insensitive request property names string propertyName = Normalize(await this.asynchronousJsonReader.ReadPropertyNameAsync().ConfigureAwait(false)); switch (propertyName) { case PropertyNameId: case PropertyNameAtomicityGroup: case PropertyNameMethod: case PropertyNameUrl: jsonProperties.Add( propertyName, await this.asynchronousJsonReader.ReadStringValueAsync().ConfigureAwait(false)); break; case PropertyNameStatus: jsonProperties.Add( propertyName, await this.asynchronousJsonReader.ReadPrimitiveValueAsync().ConfigureAwait(false)); break; case PropertyNameDependsOn: List <string> dependsOnIds = new List <string>(); await this.asynchronousJsonReader.ReadStartArrayAsync() .ConfigureAwait(false); while (this.asynchronousJsonReader.NodeType != JsonNodeType.EndArray) { dependsOnIds.Add(await this.asynchronousJsonReader.ReadStringValueAsync().ConfigureAwait(false)); } await this.asynchronousJsonReader.ReadEndArrayAsync() .ConfigureAwait(false); jsonProperties.Add(propertyName, dependsOnIds); break; case PropertyNameHeaders: ODataBatchOperationHeaders headers = new ODataBatchOperationHeaders(); // Use empty string (non-null value) to indicate that content-type header has been processed. contentTypeHeader = ""; await this.asynchronousJsonReader.ReadStartObjectAsync() .ConfigureAwait(false); while (this.asynchronousJsonReader.NodeType != JsonNodeType.EndObject) { string headerName = await this.asynchronousJsonReader.ReadPropertyNameAsync() .ConfigureAwait(false); string headerValue = (await this.asynchronousJsonReader.ReadPrimitiveValueAsync().ConfigureAwait(false)).ToString(); // Remember the Content-Type header value. if (headerName.Equals(ODataConstants.ContentTypeHeader, StringComparison.OrdinalIgnoreCase)) { contentTypeHeader = headerValue; } headers.Add(headerName, headerValue); } await this.asynchronousJsonReader.ReadEndObjectAsync() .ConfigureAwait(false); jsonProperties.Add(propertyName, headers); if (!this.isStreamPopulated && bodyContentStream != null) { // Populate the stream now since the body content has been cached and we now have content-type. await bodyContentStream.PopulateCachedBodyContentAsync(contentTypeHeader) .ConfigureAwait(false); } break; case PropertyNameBody: bodyContentStream = await CreateJsonPayloadBodyContentStreamAsync(contentTypeHeader) .ConfigureAwait(false); jsonProperties.Add(propertyName, bodyContentStream); break; default: throw new ODataException(Strings.ODataJsonLightBatchPayloadItemPropertiesCache_UnknownPropertyForMessageInBatch(propertyName)); } } // Request object end. await this.asynchronousJsonReader.ReadEndObjectAsync() .ConfigureAwait(false); } finally { // We don't need to use the Json reader anymore. this.asynchronousJsonReader = null; } }
/// <summary> /// Asynchronously reads the next node from the <paramref name="jsonReader"/> and verifies that it is a StartObject node. /// </summary> /// <param name="jsonReader">The <see cref="JsonReader"/> to read from.</param> /// <returns>A task that represents the asynchronous read operation.</returns> internal static Task ReadStartObjectAsync(this IJsonReaderAsync jsonReader) { Debug.Assert(jsonReader != null, "jsonReader != null"); return(ReadNextAsync(jsonReader, JsonNodeType.StartObject)); }