public void AddTypeNameAnnotationAsNeeded_DoesNotAddAnnotation_InDefaultMetadataMode() { // Arrange ODataComplexValue value = new ODataComplexValue(); // Act ODataComplexTypeSerializer.AddTypeNameAnnotationAsNeeded(value, ODataMetadataLevel.Default); // Assert Assert.Null(value.GetAnnotation<SerializationTypeNameAnnotation>()); }
public void AddTypeNameAnnotationAsNeeded_AddsNullAnnotation_InJsonLightNoMetadataMode() { // Arrange string expectedTypeName = "TypeName"; ODataComplexValue value = new ODataComplexValue { TypeName = expectedTypeName }; // Act ODataComplexTypeSerializer.AddTypeNameAnnotationAsNeeded(value, ODataMetadataLevel.NoMetadata); // Assert SerializationTypeNameAnnotation annotation = value.GetAnnotation<SerializationTypeNameAnnotation>(); Assert.NotNull(annotation); // Guard Assert.Null(annotation.TypeName); }
internal void WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator) { this.IncreaseRecursionDepth(); base.JsonWriter.StartObjectScope(); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } IEdmComplexTypeReference type = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)) { typeName = null; } SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } if (typeName != null) { base.JsonWriter.WriteName("__metadata"); base.JsonWriter.StartObjectScope(); base.JsonWriter.WriteName("type"); base.JsonWriter.WriteValue(typeName); base.JsonWriter.EndObjectScope(); } this.WriteProperties((type == null) ? null : type.ComplexDefinition(), complexValue.Properties, true, duplicatePropertyNamesChecker, null); base.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
/// <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(); // Write the "__metadata" : { "type": "typename" } // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely 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 = WriterValidationUtils.ResolveTypeNameForWriting(this.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed. if (typeName != null && collectionValidator != null) { string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection; if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0) { typeName = null; } } SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { typeName = serializationTypeNameAnnotation.TypeName; } if (typeName != null) { // Write the __metadata object this.JsonWriter.WriteName(JsonConstants.ODataMetadataName); this.JsonWriter.StartObjectScope(); // "type": "typename" this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.JsonWriter.WriteValue(typeName); // End the __metadata this.JsonWriter.EndObjectScope(); } // 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(); }
internal bool WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { Action action2 = null; string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } this.IncreaseRecursionDepth(); IEdmComplexTypeReference reference = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)) { typeName = null; } SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } Action beforePropertiesAction = beforeValueAction; if (typeName != null) { if (beforeValueAction != null) { if (action2 == null) { action2 = delegate { beforeValueAction(); this.WritePropertyTypeAttribute(typeName); }; } beforePropertiesAction = action2; } else { this.WritePropertyTypeAttribute(typeName); } } if (((base.MessageWriterSettings.WriterBehavior != null) && base.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior) && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker)) { IEdmComplexType definition = (IEdmComplexType) reference.Definition; if (base.Model.EpmCachedKeepPrimitiveInContent(definition) == null) { List<string> keptInContentPropertyNames = null; foreach (IEdmProperty property in from p in definition.Properties() where p.Type.IsODataPrimitiveTypeKind() select p) { EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, property.Name); if ((entityPropertyMapping != null) && entityPropertyMapping.KeepInContent) { if (keptInContentPropertyNames == null) { keptInContentPropertyNames = new List<string>(); } keptInContentPropertyNames.Add(property.Name); } } base.Model.SetAnnotationValue<CachedPrimitiveKeepInContentAnnotation>(definition, new CachedPrimitiveKeepInContentAnnotation(keptInContentPropertyNames)); } } bool flag = this.WriteProperties((reference == null) ? null : reference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforePropertiesAction, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties); this.DecreaseRecursionDepth(); return flag; }
internal bool WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } this.IncreaseRecursionDepth(); // resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata IEdmComplexTypeReference complexTypeReference = WriterValidationUtils.ResolveTypeNameForWriting(this.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed. if (typeName != null && collectionValidator != null) { string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection; if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0) { typeName = null; } } SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { typeName = serializationTypeNameAnnotation.TypeName; } Action beforeValueCallbackWithTypeName = beforeValueAction; if (typeName != null) { // The beforeValueAction (if specified) will write the actual property element start. // So if we are to write the type attribute, we must postpone that after the start element was written. // And so we chain the existing action with our type attribute writing and use that // as the before action instead. if (beforeValueAction != null) { beforeValueCallbackWithTypeName = () => { beforeValueAction(); this.WritePropertyTypeAttribute(typeName); }; } else { this.WritePropertyTypeAttribute(typeName); } } // NOTE: see the comments on ODataWriterBehavior.UseV1ProviderBehavior for more information // NOTE: We have to check for ProjectedPropertiesAnnotation.Empty here to avoid filling the cache for // complex values we are writing only to ensure we don't have nested EPM-mapped null values // that will end up in the content eventually. if (this.MessageWriterSettings.WriterBehavior != null && this.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker)) { IEdmComplexType complexType = (IEdmComplexType)complexTypeReference.Definition; CachedPrimitiveKeepInContentAnnotation keepInContentCache = this.Model.EpmCachedKeepPrimitiveInContent(complexType); if (keepInContentCache == null) { // we are about to write the first value of the given type; compute the keep-in-content information for the primitive properties of this type. List<string> keepInContentPrimitiveProperties = null; // initialize the cache with all primitive properties foreach (IEdmProperty edmProperty in complexType.Properties().Where(p => p.Type.IsODataPrimitiveTypeKind())) { // figure out the keep-in-content value EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, edmProperty.Name); if (entityPropertyMapping != null && entityPropertyMapping.KeepInContent) { if (keepInContentPrimitiveProperties == null) { keepInContentPrimitiveProperties = new List<string>(); } keepInContentPrimitiveProperties.Add(edmProperty.Name); } } this.Model.SetAnnotationValue<CachedPrimitiveKeepInContentAnnotation>(complexType, new CachedPrimitiveKeepInContentAnnotation(keepInContentPrimitiveProperties)); } } bool propertyWritten = this.WriteProperties( complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforeValueCallbackWithTypeName, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties); this.DecreaseRecursionDepth(); return propertyWritten; }