public void WriteCollectionValue(ODataCollectionValue collectionValue, IEdmTypeReference metadataTypeReference, bool isTopLevelProperty, bool isInUri, bool isOpenPropertyType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(collectionValue != null, "collectionValue != null"); Debug.Assert(!isTopLevelProperty || !isInUri, "Cannot be a top level property and in a uri"); this.IncreaseRecursionDepth(); // If the CollectionValue has type information write out the metadata and the type in it. string typeName = collectionValue.TypeName; if (isTopLevelProperty) { Debug.Assert(metadataTypeReference == null, "Never expect a metadata type for top-level properties."); if (typeName == null) { throw new ODataException(ODataErrorStrings.ODataJsonLightValueSerializer_MissingTypeNameOnCollection); } } else { // In requests, we allow the metadata type reference to be null if the type name is specified in the OM if (metadataTypeReference == null && !this.WritingResponse && typeName == null && this.Model.IsUserModel()) { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueSerializer_NoExpectedTypeOrTypeNameSpecifiedForCollectionValueInRequest); } } // 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); typeName = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, metadataTypeReference, collectionTypeReference, isOpenPropertyType); bool useValueProperty = isInUri && !string.IsNullOrEmpty(typeName); if (useValueProperty) { // "{" this.JsonWriter.StartObjectScope(); ODataJsonLightWriterUtils.WriteODataTypeInstanceAnnotation(this.JsonWriter, typeName); this.JsonWriter.WriteValuePropertyName(); } // [ // This represents the array of items in the CollectionValue 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(); 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 /*isTopLevel*/, false /*isOpenPropertyType*/, duplicatePropertyNamesChecker); duplicatePropertyNamesChecker.Clear(); } else { Debug.Assert(!(item is ODataCollectionValue), "!(item is ODataCollectionValue)"); Debug.Assert(!(item is ODataStreamReferenceValue), "!(item is ODataStreamReferenceValue)"); this.WritePrimitiveValue(item, expectedItemTypeReference); } } } // End the array scope which holds the items this.JsonWriter.EndArrayScope(); if (useValueProperty) { this.JsonWriter.EndObjectScope(); } this.DecreaseRecursionDepth(); }
public void WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isTopLevel, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); this.IncreaseRecursionDepth(); // Start the object scope which will represent the entire complex instance; // for top-level complex properties we already wrote the object scope (and the metadata URI when needed). if (!isTopLevel) { this.JsonWriter.StartObjectScope(); } string typeName = complexValue.TypeName; if (isTopLevel) { Debug.Assert(metadataTypeReference == null, "Never expect a metadata type for top-level properties."); if (typeName == null) { throw new ODataException(ODataErrorStrings.ODataJsonLightValueSerializer_MissingTypeNameOnComplex); } } else { // In requests, we allow the property type reference to be null if the type name is specified in the OM if (metadataTypeReference == null && !this.WritingResponse && typeName == null && this.Model.IsUserModel()) { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueSerializer_NoExpectedTypeOrTypeNameSpecifiedForComplexValueRequest); } } // Resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata. IEdmComplexTypeReference complexValueTypeReference = (IEdmComplexTypeReference)TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType); Debug.Assert( metadataTypeReference == null || complexValueTypeReference == null || metadataTypeReference.Definition.IsEquivalentTo(complexValueTypeReference.Definition), "Complex property types must be the same as the ones from metadata (unless open)."); typeName = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, metadataTypeReference, complexValueTypeReference, isOpenPropertyType); if (typeName != null) { ODataJsonLightWriterUtils.WriteODataTypeInstanceAnnotation(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.PropertySerializer.WriteProperties( complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(), complexValue.Properties, true /* isComplexValue */, duplicatePropertyNamesChecker, null /*projectedProperties */); // End the object scope which represents the complex instance; // for top-level complex properties we already wrote the end object scope. if (!isTopLevel) { this.JsonWriter.EndObjectScope(); } this.DecreaseRecursionDepth(); }