/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return(null); } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model); List <ODataProperty> propertyCollection = new List <ODataProperty>(); foreach (IEdmProperty property in complexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext)); } } // Try to add the dynamic properties if the complex type is open. if (complexType.ComplexDefinition().IsOpen) { List <ODataProperty> dynamicProperties = AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return(value); }
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(); }
public override ODataProperty CreateProperty(object graph, string elementName, ODataSerializerWriteContext writeContext) { if (String.IsNullOrWhiteSpace(elementName)) { throw Error.ArgumentNullOrEmpty("elementName"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } List <ODataProperty> propertyCollection = null; if (graph != null) { propertyCollection = new List <ODataProperty>(); foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported("Type {0} is not a serializable type", propertyType.FullName()); } // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter. object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null); propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext)); } } if (propertyCollection != null) { return(new ODataProperty() { Name = elementName, Value = new ODataComplexValue() { Properties = propertyCollection, TypeName = _edmComplexType.FullName() } }); } else { return(null); } }
/// <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> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null) { return(null); } List <ODataProperty> propertyCollection = new List <ODataProperty>(); foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter. object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null); propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext)); } string typeName = _edmComplexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return(value); }
/// <summary> /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class. /// </summary> /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param> public EdmComplexObject(IEdmComplexTypeReference edmType) : this(edmType.ComplexDefinition(), edmType.IsNullable) { }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (!String.IsNullOrEmpty(complexValue.TypeName) && complexType.FullName() != complexValue.TypeName) { // received a derived complex type in a base type deserializer. IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } IEdmComplexType actualType = model.FindType(complexValue.TypeName) as IEdmComplexType; if (actualType == null) { throw new ODataException(Error.Format(SRResources.ComplexTypeNotInModel, complexValue.TypeName)); } if (actualType.IsAbstract) { string message = Error.Format(SRResources.CannotInstantiateAbstractComplexType, complexValue.TypeName); throw new ODataException(message); } IEdmTypeReference actualComplexType = new EdmComplexTypeReference(actualType, isNullable: false); ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(actualComplexType); if (deserializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeDeserialized, actualComplexType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } object resource = deserializer.ReadInline(complexValue, actualComplexType, readContext); EdmStructuredObject structuredObject = resource as EdmStructuredObject; if (structuredObject != null) { structuredObject.ExpectedEdmType = complexType.ComplexDefinition(); } return(resource); } else { object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return(complexResource); } }
/// <summary> /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>. /// </summary> /// <param name="complexValue">The complex value to deserialize.</param> /// <param name="complexType">The EDM type of the complex value to read.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The deserialized complex value.</returns> public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexValue == null) { throw Error.ArgumentNull("complexValue"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (readContext.Model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (!String.IsNullOrEmpty(complexValue.TypeName) && complexType.FullName() != complexValue.TypeName) { // received a derived complex type in a base type deserializer. IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } IEdmComplexType actualType = model.FindType(complexValue.TypeName) as IEdmComplexType; if (actualType == null) { throw new ODataException(Error.Format(SRResources.ComplexTypeNotInModel, complexValue.TypeName)); } if (actualType.IsAbstract) { string message = Error.Format(SRResources.CannotInstantiateAbstractComplexType, complexValue.TypeName); throw new ODataException(message); } IEdmTypeReference actualComplexType = new EdmComplexTypeReference(actualType, isNullable: false); ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(actualComplexType); if (deserializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeDeserialized, actualComplexType.FullName(), typeof(ODataMediaTypeFormatter).Name)); } object resource = deserializer.ReadInline(complexValue, actualComplexType, readContext); EdmStructuredObject structuredObject = resource as EdmStructuredObject; if (structuredObject != null) { structuredObject.ExpectedEdmType = complexType.ComplexDefinition(); } return resource; } else { object complexResource = CreateResource(complexType, readContext); foreach (ODataProperty complexProperty in complexValue.Properties) { DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource, DeserializerProvider, readContext); } return complexResource; } }
private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataComplexValue value2 = new ODataComplexValue { TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> sourceList = new List<ODataProperty>(); bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } flag = true; base.JsonReader.SkipValue(); } else if (!ValidationUtils.IsValidPropertyName(strB)) { base.JsonReader.SkipValue(); } else { ODataProperty property = new ODataProperty { Name = strB }; IEdmProperty property2 = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { base.JsonReader.SkipValue(); continue; } ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2); object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default); if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null)) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = obj2; sourceList.Add(property); } } } base.JsonReader.ReadEndObject(); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(sourceList); this.DecreaseRecursionDepth(); return value2; }
internal void AppendDynamicProperties(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext, List<ODataProperty> propertyCollection) { PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(complexType.ComplexDefinition(), writeContext.Model); if (dynamicPropertyInfo != null) { IDictionary<string, object> dynamicPropertyDictionary = dynamicPropertyInfo.GetValue(graph) as IDictionary<string, object>; if (dynamicPropertyDictionary != null) { // build a HashSet to store the declared property names. // It is used to make sure the dynamic property name is different with the declared property name. HashSet<string> declaredPropertyNameSet = new HashSet<string>(propertyCollection.Select(a => a.Name)); foreach (KeyValuePair<string, object> dynamicProperty in dynamicPropertyDictionary) { if (dynamicProperty.Value == null) { continue; // skip the null object } Type valueType = dynamicProperty.Value.GetType(); IEdmTypeReference edmTypeReference = writeContext.Model.GetEdmTypeReference(valueType); ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, valueType.FullName, typeof(ODataComplexTypeSerializer).Name); } // try to make sure the dynamic property name is not used as declared property name. if (declaredPropertyNameSet.Contains(dynamicProperty.Key)) { throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName, dynamicProperty.Key, complexType.FullName()); } propertyCollection.Add(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext)); } } } }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value) /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValueImplementation( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.JsonReader.AssertNotBuffering(); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null?complexValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List <ODataProperty> properties = new List <ODataProperty>(); bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property. if (metadataPropertyFound) { throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } metadataPropertyFound = true; this.JsonReader.SkipValue(); } else { if (!ValidationUtils.IsValidPropertyName(propertyName)) { // We ignore properties with an invalid name since these are extension points for the future. this.JsonReader.SkipValue(); } else { // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { // in case of ignoreProperty = true which means to ignore undeclared property. this.JsonReader.SkipValue(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default, propertyName); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; properties.Add(property); } } } } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable <ODataProperty>(properties); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return(complexValue); }
/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return null; } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType); List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in complexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext)); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; }
/// <summary> /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class. /// </summary> /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param> /// <param name="assembliesResolver">The assemblies resolve to use for type resolution</param> public EdmComplexObject(IEdmComplexTypeReference edmType, AssembliesResolver assembliesResolver) : this(edmType.ComplexDefinition(), assembliesResolver, edmType.IsNullable) { }
public void CreateResource_Throws_MappingDoesNotContainEntityType() { Assert.Throws <InvalidOperationException>( () => ODataComplexTypeDeserializer.CreateResource(_addressEdmType.ComplexDefinition(), EdmCoreModel.Instance), "The provided mapping doesn't contain an entry for the entity type 'ODataDemo.Address'."); }
private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataComplexValue value2 = new ODataComplexValue { TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List <ODataProperty> sourceList = new List <ODataProperty>(); bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } flag = true; base.JsonReader.SkipValue(); } else if (!ValidationUtils.IsValidPropertyName(strB)) { base.JsonReader.SkipValue(); } else { ODataProperty property = new ODataProperty { Name = strB }; IEdmProperty property2 = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { base.JsonReader.SkipValue(); continue; } ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2); object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default); if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null)) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = obj2; sourceList.Add(property); } } } base.JsonReader.ReadEndObject(); value2.Properties = new ReadOnlyEnumerable <ODataProperty>(sourceList); this.DecreaseRecursionDepth(); return(value2); }
internal bool WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, ProjectedPropertiesAnnotation projectedProperties) { 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 = TypeNameOracle.ResolveAndValidateTypeForComplexValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType, this.WriterValidator).AsComplexOrNull(); string collectionItemTypeName; typeName = this.AtomOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexTypeReference, complexValue.GetAnnotation <SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); 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); } } bool propertyWritten = this.WriteProperties( complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(), complexValue.Properties, isWritingCollection, beforeValueCallbackWithTypeName, afterValueAction, duplicatePropertyNamesChecker, projectedProperties); this.DecreaseRecursionDepth(); return(propertyWritten); }
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 = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType).AsComplexOrNull(); string collectionItemTypeName; typeName = this.AtomOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexTypeReference, complexValue.GetAnnotation <SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); 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.EmptyProjectedPropertiesInstance)) { 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); }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value) /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValueImplementation( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.JsonReader.AssertNotBuffering(); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property. if (metadataPropertyFound) { throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } metadataPropertyFound = true; this.JsonReader.SkipValue(); } else { if (!ValidationUtils.IsValidPropertyName(propertyName)) { // We ignore properties with an invalid name since these are extension points for the future. this.JsonReader.SkipValue(); } else { // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { this.JsonReader.SkipValue(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; properties.Add(property); } } } } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return complexValue; }
/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return(null); } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model); List <IEdmProperty> settableProperties = new List <IEdmProperty>(complexType.ComplexDefinition().Properties()); if (complexObject.IsDeltaResource()) { IDelta deltaProperty = graph as IDelta; Contract.Assert(deltaProperty != null); IEnumerable <string> changedProperties = deltaProperty.GetChangedPropertyNames(); settableProperties = settableProperties.Where(p => changedProperties.Contains(p.Name)).ToList(); } List <ODataProperty> propertyCollection = new List <ODataProperty>(); foreach (IEdmProperty property in settableProperties) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { if (propertyValue != null && propertyType != null && propertyType.IsComplex()) { IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType()); if (actualType != null && propertyType != actualType) { propertyType = actualType; } } var odataProperty = propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext); if (odataProperty != null) { propertyCollection.Add(odataProperty); } } } // Try to add the dynamic properties if the complex type is open. if (complexType.ComplexDefinition().IsOpen) { List <ODataProperty> dynamicProperties = AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return(value); }
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); }
/// <summary> /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>. /// </summary> /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param> /// <param name="complexType">The EDM complex type of the object.</param> /// <param name="writeContext">The serializer context.</param> /// <returns>The created <see cref="ODataComplexValue"/>.</returns> public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext) { if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null || graph is NullEdmComplexObject) { return null; } IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model); List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in complexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataOutputFormatter).Name); } object propertyValue; if (complexObject.TryGetPropertyValue(property.Name, out propertyValue)) { if (propertyType != null && propertyType.IsComplex()) { IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType()); if (actualType != null && propertyType != actualType) { propertyType = actualType; } } propertyCollection.Add( propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext)); } } // Try to add the dynamic properties if the complex type is open. if (complexType.ComplexDefinition().IsOpen) { List<ODataProperty> dynamicProperties = AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]); if (dynamicProperties != null) { propertyCollection.AddRange(dynamicProperties); } } string typeName = complexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel); return value; }
public void WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isTopLevel, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { 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 context 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 || EdmLibraryExtensions.IsAssignableFrom(metadataTypeReference, complexValueTypeReference), "Complex property types must be the same as or inherit from 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(); }
internal void AppendDynamicProperties(object graph, IEdmComplexTypeReference complexType, ODataSerializerContext writeContext, List <ODataProperty> propertyCollection) { PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(complexType.ComplexDefinition(), writeContext.Model); if (dynamicPropertyInfo != null) { IDictionary <string, object> dynamicPropertyDictionary = dynamicPropertyInfo.GetValue(graph) as IDictionary <string, object>; if (dynamicPropertyDictionary != null) { // build a HashSet to store the declared property names. // It is used to make sure the dynamic property name is different with the declared property name. HashSet <string> declaredPropertyNameSet = new HashSet <string>(propertyCollection.Select(a => a.Name)); foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertyDictionary) { if (dynamicProperty.Value == null) { continue; // skip the null object } Type valueType = dynamicProperty.Value.GetType(); IEdmTypeReference edmTypeReference = writeContext.Model.GetEdmTypeReference(valueType); ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference); if (propertySerializer == null) { throw Error.NotSupported(SRResources.TypeCannotBeSerialized, valueType.FullName, typeof(ODataComplexTypeSerializer).Name); } // try to make sure the dynamic property name is not used as declared property name. if (declaredPropertyNameSet.Contains(dynamicProperty.Key)) { throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName, dynamicProperty.Key, complexType.FullName()); } propertyCollection.Add(propertySerializer.CreateProperty( dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext)); } } } }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - this is always initialized as necessary, do not clear.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: JsonNodeType.Property - the first property of the complex value object, or the second one if the first one was odata.type. /// JsonNodeType.EndObject - the end object of the complex value object. /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValue( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.IncreaseRecursionDepth(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.FullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (complexValueTypeReference != null) { complexValue.SetAnnotation(new ODataTypeAnnotation(complexValueTypeReference)); } List<ODataProperty> properties = new List<ODataProperty>(); while (this.JsonReader.NodeType == JsonNodeType.Property) { this.ReadPropertyCustomAnnotationValue = this.ReadCustomInstanceAnnotationValue; this.ProcessProperty( duplicatePropertyNamesChecker, this.ReadTypePropertyAnnotationValue, (propertyParsingResult, propertyName) => { switch (propertyParsingResult) { case PropertyParsingResult.ODataInstanceAnnotation: if (string.CompareOrdinal(ODataAnnotationNames.ODataType, propertyName) == 0) { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexTypeAnnotationNotFirst); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName)); } case PropertyParsingResult.CustomInstanceAnnotation: ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName); Debug.Assert( !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName), "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(annotationName) -- otherwise we should have already skipped the custom annotation and won't see it here."); var customInstanceAnnotationValue = this.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, propertyName); complexValue.InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, customInstanceAnnotationValue.ToODataValue())); break; case PropertyParsingResult.PropertyWithoutValue: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexValuePropertyAnnotationWithoutProperty(propertyName)); case PropertyParsingResult.PropertyWithValue: // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty && (this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray)) { this.JsonReader.SkipValue(); } else { // EdmLib bridge marks all key properties as non-nullable, but Astoria allows them to be nullable. // If the property has an annotation to ignore null values, we need to omit the property in requests. ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( ValidateDataPropertyTypeNameAnnotation(duplicatePropertyNamesChecker, propertyName), edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default, /*isTopLevelPropertyValue*/ false, /*insideComplexValue*/ false, propertyName, edmProperty == null); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; var propertyAnnotations = duplicatePropertyNamesChecker.GetCustomPropertyAnnotations(propertyName); if (propertyAnnotations != null) { foreach (var annotation in propertyAnnotations) { if (annotation.Value != null) { // annotation.Value == null indicates that this annotation should be skipped. property.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Key, annotation.Value.ToODataValue())); } } } properties.Add(property); } } break; case PropertyParsingResult.EndOfObject: break; case PropertyParsingResult.MetadataReferenceProperty: throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName)); } }); } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.DecreaseRecursionDepth(); return complexValue; }
protected override void ProcessComplexTypeReference(IEdmComplexTypeReference element) { this.CheckSchemaElementReference(element.ComplexDefinition()); }
/// <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(); }