/// <summary> /// Write the Verbose Json representation of an instance of a primitive type to a json writer. /// </summary> /// <param name="instance">The instance to write.</param> /// <param name="jsonWriter">Instance of JsonWriter.</param> /// <param name="typeName">Type name of the instance to write. If the type name is null, the type name will not be written in the payload.</param> /// <param name="odataVersion">The OData protocol version to be used for writing payloads.</param> public void WriteVerboseJson(object instance, IJsonWriter jsonWriter, string typeName, ODataVersion odataVersion) { IDictionary <string, object> jsonObject = GeoJsonObjectFormatter.Create().Write((ISpatial)instance); Debug.Assert(!jsonObject.ContainsKey(JsonConstants.ODataMetadataName), "__metadata should not be present in jsonObject"); jsonWriter.WriteJsonObjectValue(jsonObject, (jw) => ODataJsonWriterUtils.WriteMetadataWithTypeName(jw, typeName), odataVersion); }
/// <summary> /// Returns the string representation of the URI; Converts the URI into an absolute URI if the <paramref name="makeAbsolute"/> parameter is set to true. /// </summary> /// <param name="uri">The uri to process.</param> /// <param name="makeAbsolute">true, if the URI needs to be translated into an absolute URI; false otherwise.</param> /// <returns>If the <paramref name="makeAbsolute"/> parameter is set to true, then a string representation of an absolute URI which is either the /// specified <paramref name="uri"/> if it was absolute, or it's a combination of the BaseUri and the relative <paramref name="uri"/>; /// otherwise a string representation of the specified <paramref name="uri"/>. /// </returns> /// <remarks>This method will fail if <paramref name="makeAbsolute"/> is set to true and the specified <paramref name="uri"/> is relative and there's no base URI available.</remarks> internal string UriToUriString(Uri uri, bool makeAbsolute) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(uri != null, "uri != null"); return(ODataJsonWriterUtils.UriToUriString(this.verboseJsonOutputContext, uri, makeAbsolute)); }
/// <summary> /// Serialization to Json format string. /// </summary> /// <returns>The string in Json format</returns> internal string ToJson() { StringBuilder sb = new StringBuilder(); // Write some properties to enforce an order. foreach (KeyValuePair <string, ODataValue> keyValuePair in Properties) { if (keyValuePair.Key == JsonConstants.ODataErrorInnerErrorMessageName || keyValuePair.Key == JsonConstants.ODataErrorInnerErrorStackTraceName || keyValuePair.Key == JsonConstants.ODataErrorInnerErrorTypeNameName || keyValuePair.Key == JsonConstants.ODataErrorInnerErrorInnerErrorName) { continue; } sb.Append(","); sb.Append("\"").Append(keyValuePair.Key).Append("\"").Append(":"); ODataJsonWriterUtils.ODataValueToString(sb, keyValuePair.Value); } return(string.Format(CultureInfo.InvariantCulture, "{{" + "\"message\":\"{0}\"," + "\"type\":\"{1}\"," + "\"stacktrace\":\"{2}\"," + "\"innererror\":{3}{4}" + "}}", this.Message == null ? "" : JsonValueUtils.GetEscapedJsonString(this.Message), this.TypeName == null ? "" : JsonValueUtils.GetEscapedJsonString(this.TypeName), this.StackTrace == null ? "" : JsonValueUtils.GetEscapedJsonString(this.StackTrace), this.InnerError == null ? "{}" : this.InnerError.ToJson(), sb.ToString())); }
/// <summary> /// Write a top-level error message. /// </summary> /// <param name="error">The error instance to write.</param> /// <param name="includeDebugInformation">A flag indicating whether error details should be written (in debug mode only) or not.</param> internal void WriteTopLevelError(ODataError error, bool includeDebugInformation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(error != null, "error != null"); this.WriteTopLevelPayload(() => ODataJsonWriterUtils.WriteError(this.JsonLightOutputContext.JsonWriter, this.InstanceAnnotationWriter.WriteInstanceAnnotations, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth, /*writingJsonLight*/ true)); }
public async Task WriteErrorAsync_WritesInstanceAnnotations() { var error = new ODataError { }; error.InstanceAnnotations.Add(new ODataInstanceAnnotation("NS.AnnotationName", new ODataPrimitiveValue("AnnotationValue"))); await ODataJsonWriterUtils.WriteErrorAsync( this.jsonWriter, async (ICollection <ODataInstanceAnnotation> instanceAnnotations) => { foreach (var annotation in instanceAnnotations) { await this.jsonWriter.WriteNameAsync(JsonLightConstants.ODataPropertyAnnotationSeparatorChar + annotation.Name); await this.jsonWriter.WritePrimitiveValueAsync(((ODataPrimitiveValue)annotation.Value).Value); } }, error, includeDebugInformation : false, maxInnerErrorDepth : 0); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":{" + "\"code\":\"\"," + "\"message\":\"\"," + "\"@NS.AnnotationName\":\"AnnotationValue\"" + "}}", result); }
public async Task WriteErrorAsync_InnerErrorWithEmptyStringProperties() { var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } }, InnerError = new ODataInnerError { Message = "The other properties on the inner error object should serialize as empty strings because of using this constructor." } }; await ODataJsonWriterUtils.WriteErrorAsync( this.jsonWriter, this.writeInstanceAnnotationsDelegate, error, includeDebugInformation : true, maxInnerErrorDepth : 5); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":{" + "\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]," + "\"innererror\":{" + "\"message\":\"The other properties on the inner error object should serialize as empty strings because of using this constructor.\"," + "\"type\":\"\"," + "\"stacktrace\":\"\"" + "}" + "}}", result); }
public void StartAndEndJsonPaddingSuccessTest() { settings.JsonPCallback = "functionName"; ODataJsonWriterUtils.StartJsonPaddingIfRequired(this.jsonWriter, settings); ODataJsonWriterUtils.EndJsonPaddingIfRequired(this.jsonWriter, settings); stringWriter.GetStringBuilder().ToString().Should().Be("functionName()"); }
public async Task EndJsonPaddingIfRequiredAsync_DoesNothingIfEmptyFunctionName() { settings.JsonPCallback = ""; await ODataJsonWriterUtils.EndJsonPaddingIfRequiredAsync(this.jsonWriter, settings); Assert.Empty(stringWriter.GetStringBuilder().ToString()); }
public async Task WriteErrorAsync_WritesTargetAndDetails() { var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } } }; await ODataJsonWriterUtils.WriteErrorAsync( this.jsonWriter, this.writeInstanceAnnotationsDelegate, error, includeDebugInformation : false, maxInnerErrorDepth : 0); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":{" + "\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]" + "}}", result); }
public async Task WriteErrorAsync_InnerErrorWithCollectionAndNulls() { ODataInnerError innerError = new ODataInnerError(); innerError.Properties.Add("ResourceValue", new ODataResourceValue { Properties = new ODataProperty[] { new ODataProperty { Name = "PropertyName", Value = "PropertyValue" }, new ODataProperty { Name = "NullProperty", Value = new ODataNullValue() } } }); innerError.Properties.Add("NullProperty", new ODataNullValue()); innerError.Properties.Add("CollectionValue", new ODataCollectionValue { Items = new List <object> { new ODataNullValue(), new ODataPrimitiveValue("CollectionValue"), new ODataPrimitiveValue(1) } }); var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } }, InnerError = innerError }; await ODataJsonWriterUtils.WriteErrorAsync( this.jsonWriter, this.writeInstanceAnnotationsDelegate, error, includeDebugInformation : true, maxInnerErrorDepth : 5); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":{" + "\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]," + "\"innererror\":{" + "\"message\":\"\"," + "\"type\":\"\"," + "\"stacktrace\":\"\"," + "\"ResourceValue\":{\"PropertyName\":\"PropertyValue\",\"NullProperty\":null}," + "\"NullProperty\":null," + "\"CollectionValue\":[null,\"CollectionValue\",1]" + "}" + "}}", result); }
public void WriteError_InnerErrorWithNestedProperties() { IDictionary <string, ODataValue> properties = new Dictionary <string, ODataValue>(); properties.Add("stacktrace", "NormalString".ToODataValue()); properties.Add("MyNewObject", new ODataResourceValue() { TypeName = "ComplexValue", Properties = new List <ODataProperty>() { new ODataProperty() { Name = "NestedResourcePropertyName", Value = "NestedPropertyValue" } } }); var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } }, InnerError = new ODataInnerError(properties) { InnerError = new ODataInnerError(properties) } }; ODataJsonWriterUtils.WriteError( jsonWriter, enumerable => { }, error, includeDebugInformation: true, maxInnerErrorDepth: 5, writingJsonLight: false); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":" + "{\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]," + "\"innererror\":{" + "\"stacktrace\":\"NormalString\"," + "\"MyNewObject\":{" + "\"NestedResourcePropertyName\":\"NestedPropertyValue\"" + "}," + "\"internalexception\":{" + "\"stacktrace\":\"NormalString\"," + "\"MyNewObject\":{" + "\"NestedResourcePropertyName\":\"NestedPropertyValue\"" + "}" + "}" + "}" + "}" + "}", result); }
/// <summary> /// Writes an in-stream error. /// </summary> /// <param name="error">The error to write.</param> /// <param name="includeDebugInformation"> /// A flag indicating whether debug information (e.g., the inner error from the <paramref name="error"/>) should /// be included in the payload. This should only be used in debug scenarios. /// </param> private void WriteInStreamErrorImplementation(ODataError error, bool includeDebugInformation) { if (this.outputInStreamErrorListener != null) { this.outputInStreamErrorListener.OnInStreamError(); } ODataJsonWriterUtils.WriteError(this.JsonWriter, /*writeInstanceAnnotationsDelegate*/ null, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth, /*writingJsonLight*/ false); }
public async Task StartAndEndJsonPaddingAsync_SuccessTest() { settings.JsonPCallback = "functionName"; await ODataJsonWriterUtils.StartJsonPaddingIfRequiredAsync(this.jsonWriter, settings); await ODataJsonWriterUtils.EndJsonPaddingIfRequiredAsync(this.jsonWriter, settings); Assert.Equal("functionName()", stringWriter.GetStringBuilder().ToString()); }
/// <summary> /// Write a top-level error message. /// </summary> /// <param name="error">The error instance to write.</param> /// <param name="includeDebugInformation">A flag indicating whether error details should be written (in debug mode only) or not.</param> internal void WriteTopLevelError(ODataError error, bool includeDebugInformation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(error != null, "error != null"); // Top-level error payloads in JSON don't use the "d" wrapper even in responses! this.WriteTopLevelPayload( () => ODataJsonWriterUtils.WriteError(this.VerboseJsonOutputContext.JsonWriter, /*writeInstanceAnnotationsDelegate*/ null, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth, /*writingJsonLight*/ false), /*disableResponseWrapper*/ true); }
/// <summary> /// Writes an in-stream error. /// </summary> /// <param name="error">The error to write.</param> /// <param name="includeDebugInformation"> /// A flag indicating whether debug information (e.g., the inner error from the <paramref name="error"/>) should /// be included in the payload. This should only be used in debug scenarios. /// </param> private void WriteInStreamErrorImplementation(ODataError error, bool includeDebugInformation) { if (this.outputInStreamErrorListener != null) { this.outputInStreamErrorListener.OnInStreamError(); } JsonLightInstanceAnnotationWriter instanceAnnotationWriter = new JsonLightInstanceAnnotationWriter(new ODataJsonLightValueSerializer(this), this.TypeNameOracle); ODataJsonWriterUtils.WriteError(this.JsonWriter, instanceAnnotationWriter.WriteInstanceAnnotationsForError, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth, /*writingJsonLight*/ true); }
public async Task WriteErrorAsync_InnerErrorWithNestedProperties() { IDictionary <string, ODataValue> properties = new Dictionary <string, ODataValue>(); properties.Add("stacktrace", "NormalString".ToODataValue()); properties.Add("MyNewObject", new ODataResourceValue { TypeName = "ComplexValue", Properties = new List <ODataProperty> { new ODataProperty { Name = "NestedResourcePropertyName", Value = "NestedPropertyValue" } } }); var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } }, InnerError = new ODataInnerError(properties) { InnerError = new ODataInnerError(properties) } }; await ODataJsonWriterUtils.WriteErrorAsync( this.jsonWriter, this.writeInstanceAnnotationsDelegate, error, includeDebugInformation : true, maxInnerErrorDepth : 5); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":{" + "\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]," + "\"innererror\":{" + "\"stacktrace\":\"NormalString\"," + "\"MyNewObject\":{\"NestedResourcePropertyName\":\"NestedPropertyValue\"}," + "\"internalexception\":{" + "\"stacktrace\":\"NormalString\"," + "\"MyNewObject\":{\"NestedResourcePropertyName\":\"NestedPropertyValue\"}" + "}" + "}" + "}}", result); }
/// <summary> /// Writes the end of the enitire JSON payload. /// </summary> /// <param name="disableResponseWrapper">When set to true the "d" response wrapper won't be written even in responses</param> internal void WritePayloadEnd(bool disableResponseWrapper) { DebugUtils.CheckNoExternalCallers(); if (this.WritingResponse && !disableResponseWrapper) { // If we were writing a response payload the entire JSON is wrapped in an object scope, which we need to close here. this.JsonWriter.EndObjectScope(); } ODataJsonWriterUtils.EndJsonPaddingIfRequired(this.JsonWriter, this.MessageWriterSettings); }
/// <summary> /// Writes the start of the entire JSON payload. /// </summary> /// <param name="disableResponseWrapper">When set to true the "d" response wrapper won't be written even in responses</param> internal void WritePayloadStart(bool disableResponseWrapper) { DebugUtils.CheckNoExternalCallers(); ODataJsonWriterUtils.StartJsonPaddingIfRequired(this.JsonWriter, this.MessageWriterSettings); if (this.WritingResponse && !disableResponseWrapper) { // If we're writing a response payload the entire JSON should be wrapped in { "d": } to guard against XSS attacks // it makes the payload a valid JSON but invalid JScript statement. this.JsonWriter.StartObjectScope(); this.JsonWriter.WriteDataWrapper(); } }
/// <summary> /// Writes out the value of a complex property. /// </summary> /// <param name="complexValue">The complex value to write.</param> /// <param name="propertyTypeReference">The metadata type for the complex value.</param> /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="collectionValidator">The collection validator instance to validate the type names and type kinds of collection items; null if no validation is needed.</param> /// <remarks>The current recursion depth should be a value, measured by the number of complex and collection values between /// this complex value and the top-level payload, not including this one.</remarks> internal void WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); this.IncreaseRecursionDepth(); // Start the object scope which will represent the entire complex instance this.JsonWriter.StartObjectScope(); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } // resolve the type name to the type; if no type name is specified we will use the type inferred from metadata IEdmComplexTypeReference complexValueTypeReference = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, complexValue, isOpenPropertyType).AsComplexOrNull(); string collectionItemTypeName; typeName = this.VerboseJsonOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexValueTypeReference, complexValue.GetAnnotation <SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); // Write the "__metadata" : { "type": "typename" } // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely if (typeName != null) { ODataJsonWriterUtils.WriteMetadataWithTypeName(this.JsonWriter, typeName); } // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties. this.WriteProperties( complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(), complexValue.Properties, true /* isComplexValue */, duplicatePropertyNamesChecker, null /*projectedProperties */); // End the object scope which represents the complex instance this.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
/// <summary> /// Asynchronously writes a top-level error message. /// </summary> /// <param name="error">The error instance to write.</param> /// <param name="includeDebugInformation">A flag indicating whether error details should be written (in debug mode only) or not.</param> /// <returns>A task that represents the asynchronous write operation.</returns> internal Task WriteTopLevelErrorAsync(ODataError error, bool includeDebugInformation) { Debug.Assert(error != null, "error != null"); return(this.WriteTopLevelPayloadAsync( () => { return ODataJsonWriterUtils.WriteErrorAsync( this.AsynchronousJsonWriter, this.InstanceAnnotationWriter.WriteInstanceAnnotationsForErrorAsync, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth); })); }
public async Task WriteErrorAsync_ShouldThrowArgumentNullException_ForWriteInstanceAnnotationsDelegateIsNull() { var error = new ODataError { }; await Assert.ThrowsAsync <ArgumentNullException>( "writeInstanceAnnotationsDelegate", async() => { await ODataJsonWriterUtils.WriteErrorAsync( this.jsonWriter, null, error, includeDebugInformation: false, maxInnerErrorDepth: 0); }); }
public void WriteError_WritesTargetAndDetails() { var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } } }; ODataJsonWriterUtils.WriteError( jsonWriter, enumerable => { }, error, includeDebugInformation: false, maxInnerErrorDepth: 0, writingJsonLight: false); var result = stringWriter.GetStringBuilder().ToString(); result.Should().Be(@"{""error"":{""code"":"""",""message"":"""",""target"":""any target""," + @"""details"":[{""code"":""500"",""target"":""any target"",""message"":""any msg""}]}}"); }
public void WriteError_InnerErrorWithEmptyStringProperties() { var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } }, InnerError = new ODataInnerError() { Message = "The other properties on the inner error object should serialize as empty strings because of using this constructor." } }; ODataJsonWriterUtils.WriteError( jsonWriter, enumerable => { }, error, includeDebugInformation: true, maxInnerErrorDepth: 5, writingJsonLight: false); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":" + "{\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]," + "\"innererror\":{" + "\"message\":\"The other properties on the inner error object should serialize as empty strings because of using this constructor.\"," + "\"type\":\"\"," + "\"stacktrace\":\"\"" + "}" + "}" + "}", result); }
internal void WritePayloadEnd() { DebugUtils.CheckNoExternalCallers(); ODataJsonWriterUtils.EndJsonPaddingIfRequired(this.JsonWriter, this.MessageWriterSettings); }
public void WriteError_InnerErrorWithCollectionAndNulls() { ODataInnerError innerError = new ODataInnerError(); innerError.Properties.Add("ResourceValue", new ODataResourceValue() { Properties = new ODataProperty[] { new ODataProperty() { Name = "PropertyName", Value = "PropertyValue" }, new ODataProperty() { Name = "NullProperty", Value = new ODataNullValue() } } }); innerError.Properties.Add("NullProperty", new ODataNullValue()); innerError.Properties.Add("CollectionValue", new ODataCollectionValue() { Items = new List <object>() { new ODataNullValue(), new ODataPrimitiveValue("CollectionValue"), new ODataPrimitiveValue(1) } }); var error = new ODataError { Target = "any target", Details = new[] { new ODataErrorDetail { ErrorCode = "500", Target = "any target", Message = "any msg" } }, InnerError = innerError }; ODataJsonWriterUtils.WriteError( jsonWriter, enumerable => { }, error, includeDebugInformation: true, maxInnerErrorDepth: 5, writingJsonLight: false); var result = stringWriter.GetStringBuilder().ToString(); Assert.Equal("{\"error\":" + "{\"code\":\"\"," + "\"message\":\"\"," + "\"target\":\"any target\"," + "\"details\":[{\"code\":\"500\",\"target\":\"any target\",\"message\":\"any msg\"}]," + "\"innererror\":{" + "\"message\":\"\"," + "\"type\":\"\"," + "\"stacktrace\":\"\"," + "\"ResourceValue\":{" + "\"PropertyName\":\"PropertyValue\"," + "\"NullProperty\":null" + "}," + "\"NullProperty\":null," + "\"CollectionValue\":[null,\"CollectionValue\",1]" + "}" + "}" + "}", result); }
public void EndJsonPaddingIfRequiredWillDoNothingIfNullFunctionName() { settings.JsonPCallback = null; ODataJsonWriterUtils.EndJsonPaddingIfRequired(this.jsonWriter, settings); Assert.Empty(stringWriter.GetStringBuilder().ToString()); }
public void EndJsonPaddingIfRequiredWillDoNothingIfEmptyFunctionName() { settings.JsonPCallback = ""; ODataJsonWriterUtils.EndJsonPaddingIfRequired(this.jsonWriter, settings); stringWriter.GetStringBuilder().ToString().Should().BeEmpty(); }
/// <summary> /// Writes out the value of a collection property. /// </summary> /// <param name="collectionValue">The collection value to write.</param> /// <param name="metadataTypeReference">The metadata type reference for the collection.</param> /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param> /// <remarks>The current recursion depth is measured by the number of complex and collection values between /// this one and the top-level payload, not including this one.</remarks> internal void WriteCollectionValue( ODataCollectionValue collectionValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(collectionValue != null, "collectionValue != null"); this.IncreaseRecursionDepth(); // Start the object scope which will represent the entire CollectionValue instance this.JsonWriter.StartObjectScope(); // resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, metadataTypeReference, collectionValue, isOpenPropertyType); // "__metadata": { "type": "typename" } // If the CollectionValue has type information write out the metadata and the type in it. string collectionItemTypeName; string typeName = this.VerboseJsonOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, collectionTypeReference, collectionValue.GetAnnotation <SerializationTypeNameAnnotation>(), /*collectionValidator*/ null, out collectionItemTypeName); if (typeName != null) { ODataJsonWriterUtils.WriteMetadataWithTypeName(this.JsonWriter, typeName); } // "results": [ // This represents the array of items in the CollectionValue this.JsonWriter.WriteDataArrayName(); this.JsonWriter.StartArrayScope(); // Iterate through the CollectionValue items and write them out (treat null Items as an empty enumeration) IEnumerable items = collectionValue.Items; if (items != null) { IEdmTypeReference expectedItemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType(); CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(collectionItemTypeName); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null; foreach (object item in items) { ValidationUtils.ValidateCollectionItem(item, false /* isStreamable */); ODataComplexValue itemAsComplexValue = item as ODataComplexValue; if (itemAsComplexValue != null) { if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } this.WriteComplexValue( itemAsComplexValue, expectedItemTypeReference, false, duplicatePropertyNamesChecker, collectionValidator); duplicatePropertyNamesChecker.Clear(); } else { Debug.Assert(!(item is ODataCollectionValue), "!(item is ODataCollectionValue)"); Debug.Assert(!(item is ODataStreamReferenceValue), "!(item is ODataStreamReferenceValue)"); this.WritePrimitiveValue(item, collectionValidator, expectedItemTypeReference); } } } // End the array scope which holds the items this.JsonWriter.EndArrayScope(); // End the object scope which holds the entire collection this.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
/// <summary> /// Asynchronously writes the end of the entire JSON payload. /// </summary> /// <returns>A task that represents the asynchronous write operation.</returns> internal Task WritePayloadEndAsync() { return(ODataJsonWriterUtils.EndJsonPaddingIfRequiredAsync(this.AsynchronousJsonWriter, this.MessageWriterSettings)); }
internal void WritePayloadEnd() { ODataJsonWriterUtils.EndJsonPaddingIfRequired(this.JsonWriter, this.MessageWriterSettings); }