private void ReadPropertiesImplementation(IEdmStructuredType structuredType, List <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { if (!base.XmlReader.IsEmptyElement) { base.XmlReader.ReadStartElement(); do { switch (base.XmlReader.NodeType) { case XmlNodeType.Element: if (base.XmlReader.NamespaceEquals(base.XmlReader.ODataNamespace)) { IEdmProperty property = null; bool flag = false; bool ignoreProperty = false; if (structuredType != null) { property = ReaderValidationUtils.ValidateValuePropertyDefined(base.XmlReader.LocalName, structuredType, base.MessageReaderSettings, out ignoreProperty); if ((property != null) && (property.PropertyKind == EdmPropertyKind.Navigation)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(property.Name, structuredType)); } flag = property == null; } if (ignoreProperty) { base.XmlReader.Skip(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = (base.ReadingResponse || (property == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property); ODataProperty property2 = this.ReadProperty((property == null) ? null : property.Type, nullValueReadBehaviorKind, epmPresent); if (property2 != null) { if (flag) { ValidationUtils.ValidateOpenPropertyValue(property2.Name, property2.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property2); properties.Add(property2); } } } else { base.XmlReader.Skip(); } break; case XmlNodeType.EndElement: break; default: base.XmlReader.Skip(); break; } }while (base.XmlReader.NodeType != XmlNodeType.EndElement); } }
/// <summary> /// Writes a stream property to the ATOM payload /// </summary> /// <param name="streamProperty">The stream property to create the payload for.</param> /// <param name="owningType">The <see cref="IEdmEntityType"/> instance for which the stream property defined on.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> internal void WriteStreamProperty( ODataProperty streamProperty, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(streamProperty != null, "Stream property must not be null."); Debug.Assert(streamProperty.Value != null, "The media resource of the stream property must not be null."); WriterValidationUtils.ValidatePropertyNotNull(streamProperty); string propertyName = streamProperty.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(streamProperty.Name, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); WriterValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty, this.Version, this.WritingResponse); ODataStreamReferenceValue streamReferenceValue = (ODataStreamReferenceValue)streamProperty.Value; WriterValidationUtils.ValidateStreamReferenceValue(streamReferenceValue, false /*isDefaultStream*/); if (owningType != null && owningType.IsOpen && edmProperty == null) { ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, streamReferenceValue, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); } AtomStreamReferenceMetadata streamReferenceMetadata = streamReferenceValue.GetAnnotation <AtomStreamReferenceMetadata>(); string contentType = streamReferenceValue.ContentType; string linkTitle = streamProperty.Name; Uri readLink = streamReferenceValue.ReadLink; if (readLink != null) { string readLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, false); AtomLinkMetadata readLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.SelfLink; AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(readLinkMetadata, readLinkRelation, readLink, linkTitle, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, null /* etag */); } Uri editLink = streamReferenceValue.EditLink; if (editLink != null) { string editLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, true); AtomLinkMetadata editLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.EditLink; AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(editLinkMetadata, editLinkRelation, editLink, linkTitle, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, streamReferenceValue.ETag); } }
private void WriteProperty(ODataProperty property, IEdmStructuredType owningType, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); if (!projectedProperties.ShouldSkipProperty(property.Name)) { WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty expectedProperty = WriterValidationUtils.ValidatePropertyDefined(property.Name, owningType); if (((expectedProperty != null) && expectedProperty.Type.IsSpatial()) || ((expectedProperty == null) && (property.Value is ISpatial))) { ODataVersionChecker.CheckSpatialValue(base.Version); } base.JsonWriter.WriteName(property.Name); object obj2 = property.Value; if (obj2 == null) { WriterValidationUtils.ValidateNullPropertyValue(expectedProperty, base.MessageWriterSettings.WriterBehavior, base.Model); base.JsonWriter.WriteValue((string)null); } else { bool isOpenPropertyType = ((owningType != null) && owningType.IsOpen) && (expectedProperty == null); if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(property.Name, obj2); } IEdmTypeReference propertyTypeReference = (expectedProperty == null) ? null : expectedProperty.Type; ODataComplexValue complexValue = obj2 as ODataComplexValue; if (complexValue != null) { this.WriteComplexValue(complexValue, propertyTypeReference, isOpenPropertyType, base.CreateDuplicatePropertyNamesChecker(), null); } else { ODataCollectionValue collectionValue = obj2 as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(base.Version, property.Name); this.WriteCollectionValue(collectionValue, propertyTypeReference, isOpenPropertyType); } else if (obj2 is ODataStreamReferenceValue) { if (!allowStreamProperty) { throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(property.Name)); } WriterValidationUtils.ValidateStreamReferenceProperty(property, expectedProperty, base.Version, base.WritingResponse); this.WriteStreamReferenceValue((ODataStreamReferenceValue)property.Value); } else { this.WritePrimitiveValue(obj2, null, propertyTypeReference); } } } } }
private void WriteAssociationLink(ODataAssociationLink associationLink, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink); base.JsonWriter.WriteName(associationLink.Name); base.JsonWriter.StartObjectScope(); base.JsonWriter.WriteName("associationuri"); base.JsonWriter.WriteValue(base.UriToAbsoluteUriString(associationLink.Url)); base.JsonWriter.EndObjectScope(); }
internal void WriteAssociationLink(ODataAssociationLink associationLink, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { ValidationUtils.ValidateAssociationLinkNotNull(associationLink); if (!projectedProperties.ShouldSkipProperty(associationLink.Name)) { base.ValidateAssociationLink(associationLink, owningType); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink); AtomLinkMetadata annotation = associationLink.GetAnnotation <AtomLinkMetadata>(); string relation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink); AtomLinkMetadata linkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(annotation, relation, associationLink.Url, associationLink.Name, "application/xml"); this.atomEntryMetadataSerializer.WriteAtomLink(linkMetadata, null); } }
/// <summary> /// Writes the metadata content for an association link /// </summary> /// <param name="associationLink">The association link to write.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> private void WriteAssociationLink( ODataAssociationLink associationLink, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { DebugUtils.CheckNoExternalCallers(); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink); // Write the "LinkName": { this.JsonWriter.WriteName(associationLink.Name); this.JsonWriter.StartObjectScope(); // Write the "associationuri": "url" this.JsonWriter.WriteName(JsonConstants.ODataMetadataPropertiesAssociationUriName); this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(associationLink.Url)); // Close the "LinkName" object this.JsonWriter.EndObjectScope(); }
/// <summary> /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal. /// </summary> /// <param name="associationLink">The association link for which to write the metadata.</param> /// <param name="owningType">The <see cref="IEdmEntityType"/> instance the association link is defined on.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> internal void WriteAssociationLink( ODataAssociationLink associationLink, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); ValidationUtils.ValidateAssociationLinkNotNull(associationLink); if (projectedProperties.ShouldSkipProperty(associationLink.Name)) { return; } this.ValidateAssociationLink(associationLink, owningType); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink); AtomLinkMetadata linkMetadata = associationLink.GetAnnotation <AtomLinkMetadata>(); string linkRelation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink); AtomLinkMetadata mergedLinkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(linkMetadata, linkRelation, associationLink.Url, associationLink.Name, MimeConstants.MimeApplicationXml); this.atomEntryMetadataSerializer.WriteAtomLink(mergedLinkMetadata, null /* etag*/); }
internal void WriteStreamProperty(ODataProperty streamProperty, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(streamProperty); string name = streamProperty.Name; if (!projectedProperties.ShouldSkipProperty(name)) { WriterValidationUtils.ValidateProperty(streamProperty); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(streamProperty.Name, owningType); WriterValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty, base.Version, base.WritingResponse); ODataStreamReferenceValue value2 = (ODataStreamReferenceValue)streamProperty.Value; if (((owningType != null) && owningType.IsOpen) && (edmProperty == null)) { ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, value2); } AtomStreamReferenceMetadata annotation = value2.GetAnnotation <AtomStreamReferenceMetadata>(); string contentType = value2.ContentType; string title = streamProperty.Name; Uri readLink = value2.ReadLink; if (readLink != null) { string relation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, false); AtomLinkMetadata metadata = (annotation == null) ? null : annotation.SelfLink; AtomLinkMetadata linkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(metadata, relation, readLink, title, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(linkMetadata, null); } Uri editLink = value2.EditLink; if (editLink != null) { string str5 = AtomUtils.ComputeStreamPropertyRelation(streamProperty, true); AtomLinkMetadata metadata4 = (annotation == null) ? null : annotation.EditLink; AtomLinkMetadata metadata5 = ODataAtomWriterMetadataUtils.MergeLinkMetadata(metadata4, str5, editLink, title, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(metadata5, value2.ETag); } } }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The owning type for the <paramref name="property"/> or null if no metadata is available.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a top-level collection instead of an entry.</param> /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if the property was actually written, false otherwise.</returns> private bool WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); object value = property.Value; string propertyName = property.Name; //// TODO: If we implement type conversions the value needs to be converted here //// since the next method call needs to know if the value is a string or not in some cases. ODataComplexValue complexValue = value as ODataComplexValue; ProjectedPropertiesAnnotation complexValueProjectedProperties = null; if (!ShouldWritePropertyInContent(projectedProperties, propertyName)) { return(false); } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (value is ODataStreamReferenceValue) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } // Null property value. if (value == null) { this.WriteNullPropertyValue(propertyTypeReference, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } if (complexValue != null) { return(this.WriteComplexValueProperty( complexValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType, complexValueProjectedProperties)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionValueProperty( collectionValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType); return(true); } // If the value isn't one of the value types tested for already, it must be a non-null primitive or enum type. this.WritePropertyStart(beforePropertyAction, property, isWritingCollection, isTopLevel); SerializationTypeNameAnnotation serializationTypeNameAnnotation = property.ODataValue.GetAnnotation <SerializationTypeNameAnnotation>(); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { this.WriteEnumValue(enumValue, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); } else { this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); } this.WritePropertyEnd(); return(true); }
/// <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; }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = null; IEdmTypeReference propertyTypeReference = null; if (this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation) { edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); propertyTypeReference = edmProperty == null ? null : edmProperty.Type; } ODataValue value = property.ODataValue; ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName; if (value is ODataNullValue || value == null) { WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model); if (isTopLevel) { // Write the special null marker for top-level null properties. this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNull); this.JsonWriter.WriteValue(true); } else { this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteNullValue(); } return; } bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty); if (isOpenPropertyType && this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { if (!isTopLevel) { this.JsonWriter.WriteName(wirePropertyName); } this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(enumValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteEnumValue(enumValue, propertyTypeReference); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); // passing false for 'isTopLevel' because the outer wrapping object has already been written. this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType); } else { Debug.Assert(primitiveValue != null, "primitiveValue != null"); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference); } }
/// <summary> /// Writes a stream property to the ATOM payload /// </summary> /// <param name="streamProperty">The stream property to create the payload for.</param> /// <param name="owningType">The <see cref="IEdmEntityType"/> instance for which the stream property defined on.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> internal void WriteStreamProperty( ODataProperty streamProperty, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(streamProperty != null, "Stream property must not be null."); Debug.Assert(streamProperty.Value != null, "The media resource of the stream property must not be null."); WriterValidationUtils.ValidatePropertyNotNull(streamProperty); string propertyName = streamProperty.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidateProperty(streamProperty); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(streamProperty.Name, owningType); WriterValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty, this.Version, this.WritingResponse); ODataStreamReferenceValue streamReferenceValue = (ODataStreamReferenceValue)streamProperty.Value; if (owningType != null && owningType.IsOpen && edmProperty == null) { ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, streamReferenceValue); } AtomStreamReferenceMetadata streamReferenceMetadata = streamReferenceValue.GetAnnotation<AtomStreamReferenceMetadata>(); string contentType = streamReferenceValue.ContentType; string linkTitle = streamProperty.Name; Uri readLink = streamReferenceValue.ReadLink; if (readLink != null) { string readLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, false); AtomLinkMetadata readLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.SelfLink; AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(readLinkMetadata, readLinkRelation, readLink, linkTitle, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, null /* etag */); } Uri editLink = streamReferenceValue.EditLink; if (editLink != null) { string editLinkRelation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, true); AtomLinkMetadata editLinkMetadata = streamReferenceMetadata == null ? null : streamReferenceMetadata.EditLink; AtomLinkMetadata mergedMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(editLinkMetadata, editLinkRelation, editLink, linkTitle, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(mergedMetadata, streamReferenceValue.ETag); } }
/// <summary> /// Writes a name/value pair for a property. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The type owning the property (or null if no metadata is available).</param> /// <param name="allowStreamProperty">Should pass in true if we are writing a property of an ODataEntry instance, false otherwise. /// Named stream properties should only be defined on ODataEntry instances.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); if (projectedProperties.ShouldSkipProperty(property.Name)) { return; } WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(property.Name, owningType); // If the property is of Geography or Geometry type or the value is of Geography or Geometry type // make sure to check that the version is 3.0 or above. if ((edmProperty != null && edmProperty.Type.IsSpatial()) || (edmProperty == null && property.Value is System.Spatial.ISpatial)) { ODataVersionChecker.CheckSpatialValue(this.Version); } this.JsonWriter.WriteName(property.Name); object value = property.Value; if (value == null) { WriterValidationUtils.ValidateNullPropertyValue(edmProperty, this.MessageWriterSettings.WriterBehavior, this.Model); this.JsonWriter.WriteValue(null); } else { bool isOpenPropertyType = owningType != null && owningType.IsOpen && edmProperty == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(property.Name, value); } IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { this.WriteComplexValue( complexValue, propertyTypeReference, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker(), /*collectionValidator*/ null); } else { ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(this.Version, property.Name); this.WriteCollectionValue( collectionValue, propertyTypeReference, isOpenPropertyType); } else { ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(o.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(property.Name)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse); this.WriteStreamReferenceValue((ODataStreamReferenceValue)property.Value); } else { this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference); } } } } }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The owning type for the <paramref name="property"/> or null if no metadata is available.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a top-level collection instead of an entry.</param> /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</param> /// <param name="epmValueCache">Cache of values used in EPM so that we avoid multiple enumerations of properties/items. (can be null)</param> /// <param name="epmParentSourcePathSegment">The EPM source path segment which points to the property which sub-property we're writing. (can be null)</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if the property was actually written, false otherwise.</returns> private bool WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, EpmValueCache epmValueCache, EpmSourcePathSegment epmParentSourcePathSegment, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); object value = property.Value; string propertyName = property.Name; EpmSourcePathSegment epmSourcePathSegment = EpmWriterUtils.GetPropertySourcePathSegment(epmParentSourcePathSegment, propertyName); //// TODO: If we implement type conversions the value needs to be converted here //// since the next method call needs to know if the value is a string or not in some cases. ODataComplexValue complexValue = value as ODataComplexValue; ProjectedPropertiesAnnotation complexValueProjectedProperties = null; if (!this.ShouldWritePropertyInContent(owningType, projectedProperties, propertyName, value, epmSourcePathSegment)) { // If ShouldWritePropertyInContent returns false for a comlex value we have to continue // writing the property but set the projectedProperties to an empty array. The reason for this // is that we might find EPM on a nested property that has a null value and thus must be written // in content (in which case the parent property also has to be written). // This only applies if we have EPM information for the property. if (epmSourcePathSegment != null && complexValue != null) { Debug.Assert(!projectedProperties.IsPropertyProjected(propertyName), "ShouldWritePropertyInContent must not return false for a projected complex property."); complexValueProjectedProperties = ProjectedPropertiesAnnotation.EmptyProjectedPropertiesInstance; } else { return(false); } } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (value is ODataStreamReferenceValue) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } // If the property is of Geography or Geometry type or the value is of Geography or Geometry type // make sure to check that the version is 3.0 or above. if ((propertyTypeReference != null && propertyTypeReference.IsSpatial()) || (propertyTypeReference == null && value is System.Spatial.ISpatial)) { ODataVersionChecker.CheckSpatialValue(this.Version); } // Null property value. if (value == null) { this.WriteNullPropertyValue(propertyTypeReference, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); } if (complexValue != null) { return(this.WriteComplexValueProperty( complexValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, epmValueCache, propertyTypeReference, isOpenPropertyType, epmSourcePathSegment, complexValueProjectedProperties)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionValueProperty( collectionValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType); return(true); } // If the value isn't one of the value types tested for already, it must be a non-null primitive. this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); SerializationTypeNameAnnotation serializationTypeNameAnnotation = property.ODataValue.GetAnnotation <SerializationTypeNameAnnotation>(); this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); this.WritePropertyEnd(); return(true); }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName, bypassValidation); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); if (property.InstanceAnnotations.Any()) { if (isTopLevel) { this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations); } else { this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations, propertyName); } } IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined( propertyName, owningType, !this.bypassValidation); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; ODataValue value = property.ODataValue; ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.WritingResponse, this.bypassValidation); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName; if (value is ODataNullValue || value == null) { WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model, this.bypassValidation); if (isTopLevel) { // Write the special null marker for top-level null properties. this.ODataAnnotationWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNull); this.JsonWriter.WriteValue(true); } else { this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteNullValue(); } return; } bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty); if (isOpenPropertyType && this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { if (!isTopLevel) { this.JsonWriter.WriteName(wirePropertyName); } this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { // This is a work around, needTypeOnWire always = true for client side: // ClientEdmModel's reflection can't know a property is open type even if it is, so here // make client side always write 'odata.type' for enum. bool needTypeOnWire = string.Equals(this.JsonLightOutputContext.Model.GetType().Name, "ClientEdmModel", StringComparison.OrdinalIgnoreCase); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting( enumValue, propertyTypeReference, typeFromValue, needTypeOnWire ? true /* leverage this flag to write 'odata.type' */ : isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteEnumValue(enumValue, propertyTypeReference); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); // passing false for 'isTopLevel' because the outer wrapping object has already been written. this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType); } else { ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; Debug.Assert(primitiveValue != null, "primitiveValue != null"); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference); } }
/// <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); }
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); }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); bool shouldWriteRawAnnotations = false; if (!ShouldWriteProperty(owningType, property, edmProperty, out shouldWriteRawAnnotations)) { return; } IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; bool alreadyWroteODataType = false; if (shouldWriteRawAnnotations) { TryWriteRawAnnotations(property, out alreadyWroteODataType); } // handle ODataUntypedValue ODataUntypedValue untypedValue = property.Value as ODataUntypedValue; if (untypedValue != null) { if (this.MessageWriterSettings.ContainUndeclaredPropertyBehavior( ODataUndeclaredPropertyBehaviorKinds.SupportUndeclaredValueProperty)) { this.JsonWriter.WriteName(propertyName); this.JsonWriter.WriteRawString(untypedValue.RawJson); } return; } ODataValue value = property.ODataValue; ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; // If the property is of Geography or Geometry type or the value is of Geography or Geometry type // make sure to check that the version is 3.0 or above. bool isSpatial = (propertyTypeReference != null && propertyTypeReference.IsSpatial()) || (propertyTypeReference == null && primitiveValue != null && primitiveValue.Value is ISpatial); if (isSpatial) { ODataVersionChecker.CheckSpatialValue(this.Version); } ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName; if (value is ODataNullValue || value == null) { WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model); if (isTopLevel) { // Write the special null marker for top-level null properties. this.JsonWriter.WriteName(ODataAnnotationNames.ODataNull); this.JsonWriter.WriteValue(true); } else { this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteNullValue(); } return; } bool isOpenPropertyType = IsOpenPropertyType(property, owningType, edmProperty); if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { if (!isTopLevel) { this.JsonWriter.WriteName(wirePropertyName); } this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType); ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { if (!alreadyWroteODataType) { string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel); } this.JsonWriter.WriteName(wirePropertyName); ODataVersionChecker.CheckCollectionValueProperties(this.Version, propertyName); // passing false for 'isTopLevel' because the outer wrapping object has already been written. this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType); return; } Debug.Assert(primitiveValue != null, "primitiveValue != null"); if (!alreadyWroteODataType) { string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); } this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference); }
/// <summary> /// Reads the content of a properties in an element (complex value, m:properties, ...) /// </summary> /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param> /// <param name="properties">The list of properties to add properties to.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The element to read properties from. /// Post-Condition: XmlNodeType.Element - The element to read properties from if it is an empty element. /// XmlNodeType.EndElement - The end element of the element to read properties from. /// </remarks> private void ReadPropertiesImplementation(IEdmStructuredType structuredType, ReadOnlyEnumerable<ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(properties != null, "properties != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertXmlCondition(XmlNodeType.Element); // Empty values are valid - they have no properties if (!this.XmlReader.IsEmptyElement) { // Read over the complex value element to its first child node (or end-element) this.XmlReader.ReadStartElement(); // WCF DS will skip over the rest of the complex value or entity properties if the first element in it is preceded with // a text node. Once the first element is found (no matter its namespace) then the non-element nodes // are ignored but skipped and the reading continues. // For ODataLib we should not do this and probably just ignore the text node even at the beginning (to be consistent). do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { // Found a property IEdmProperty edmProperty = null; bool isOpen = false; bool ignoreProperty = false; if (structuredType != null) { // Lookup the property in metadata edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty); if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation) { throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType)); } // If the property was not declared, it must be open. isOpen = edmProperty == null; } if (ignoreProperty) { this.XmlReader.Skip(); } 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); ODataProperty property = this.ReadProperty( false, edmProperty == null ? null : edmProperty.Name, edmProperty == null ? null : edmProperty.Type, nullValueReadBehaviorKind); Debug.Assert( property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue, "If we don't ignore null values the property must not be null."); if (property != null) { if (isOpen) { ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); properties.AddToSourceList(property); } } } else { this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // End of the complex value. break; default: // Non-element so for example a text node, just ignore this.XmlReader.Skip(); break; } } while (this.XmlReader.NodeType != XmlNodeType.EndElement); } }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The type owning the property (or null if no metadata is available).</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a collection instead of an entry.</param> /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</param> /// <param name="epmValueCache">Cache of values used in EPM so that we avoid multiple enumerations of properties/items. (can be null)</param> /// <param name="epmParentSourcePathSegment">The EPM source path segment which points to the property which sub-property we're writing. (can be null)</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if the property was actually written, false otherwise.</returns> private bool WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, EpmValueCache epmValueCache, EpmSourcePathSegment epmParentSourcePathSegment, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); object value = property.Value; string propertyName = property.Name; EpmSourcePathSegment epmSourcePathSegment = EpmWriterUtils.GetPropertySourcePathSegment(epmParentSourcePathSegment, propertyName); //// TODO: If we implement type conversions the value needs to be converted here //// since the next method call needs to know if the value is a string or not in some cases. ODataComplexValue complexValue = value as ODataComplexValue; ProjectedPropertiesAnnotation complexValueProjectedProperties = null; if (!this.ShouldWritePropertyInContent(owningType, projectedProperties, propertyName, value, epmSourcePathSegment)) { // If ShouldWritePropertyInContent returns false for a comlex value we have to continue // writing the property but set the projectedProperties to an empty array. The reason for this // is that we might find EPM on a nested property that has a null value and thus must be written // in content (in which case the parent property also has to be written). // This only applies if we have EPM information for the property. if (epmSourcePathSegment != null && complexValue != null) { Debug.Assert(!projectedProperties.IsPropertyProjected(propertyName), "ShouldWritePropertyInContent must not return false for a projected complex property."); complexValueProjectedProperties = ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker; } else { return(false); } } WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); if (value is ODataStreamReferenceValue) { throw new ODataException(o.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } // If the property is of Geography or Geometry type or the value is of Geography or Geometry type // make sure to check that the version is 3.0 or above. if ((edmProperty != null && edmProperty.Type.IsSpatial()) || (edmProperty == null && value is System.Spatial.ISpatial)) { ODataVersionChecker.CheckSpatialValue(this.Version); } // Null property value. if (value == null) { this.WriteNullPropertyValue(edmProperty, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = owningType != null && owningType.IsOpen && edmProperty == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (complexValue != null) { // Complex properties are written recursively. DuplicatePropertyNamesChecker complexValuePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); if (isTopLevel) { // Top-level property must always write the property element Debug.Assert(complexValueProjectedProperties == null, "complexValueProjectedProperties == null"); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.AssertRecursionDepthIsZero(); this.WriteComplexValue( complexValue, propertyTypeReference, isOpenPropertyType, isWritingCollection, null /* beforeValueAction */, null /* afterValueAction */, complexValuePropertyNamesChecker, null /* collectionValidator */, epmValueCache, epmSourcePathSegment, null /* projectedProperties */); this.AssertRecursionDepthIsZero(); this.WritePropertyEnd(); return(true); } return(this.WriteComplexValue( complexValue, propertyTypeReference, isOpenPropertyType, isWritingCollection, () => this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel), () => this.WritePropertyEnd(), complexValuePropertyNamesChecker, null /* collectionValidator */, epmValueCache, epmSourcePathSegment, complexValueProjectedProperties)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(this.Version, propertyName); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WriteCollectionValue( collectionValue, propertyTypeReference, isOpenPropertyType, isWritingCollection); this.WritePropertyEnd(); return(true); } this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference); this.WritePropertyEnd(); return(true); }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { this.WriterValidator.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } this.WriterValidator.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); WriteInstanceAnnotation(property, isTopLevel); bool throwOnMissingProperty = this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation && !this.WritingResponse; IEdmProperty edmProperty = this.WriterValidator.ValidatePropertyDefined( propertyName, owningType, throwOnMissingProperty); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; ODataValue value = property.ODataValue; ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); this.WriterValidator.ValidateStreamReferenceProperty(property, edmProperty, this.WritingResponse); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } if (value is ODataNullValue || value == null) { this.WriteNullProperty(property, propertyTypeReference, isTopLevel); return; } bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty); ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; if (primitiveValue != null) { this.WritePrimitiveProperty(property, primitiveValue, propertyTypeReference, isTopLevel, isOpenPropertyType); return; } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { this.WriteComplexProperty(property, complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType); return; } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { this.WriteEnumProperty(property, enumValue, propertyTypeReference, isTopLevel, isOpenPropertyType); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionProperty(property, collectionValue, propertyTypeReference, isTopLevel, isOpenPropertyType); return; } else { ODataUntypedValue untypedValue = value as ODataUntypedValue; this.WriteUntypedProperty(property, untypedValue, isTopLevel); return; } }
private bool WriteProperty(ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, EpmValueCache epmValueCache, EpmSourcePathSegment epmParentSourcePathSegment, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { Action beforeValueAction = null; Action afterValueAction = null; WriterValidationUtils.ValidatePropertyNotNull(property); object propertyValue = property.Value; string propertyName = property.Name; EpmSourcePathSegment propertySourcePathSegment = EpmWriterUtils.GetPropertySourcePathSegment(epmParentSourcePathSegment, propertyName); ODataComplexValue complexValue = propertyValue as ODataComplexValue; ProjectedPropertiesAnnotation emptyProjectedPropertiesMarker = null; if (!this.ShouldWritePropertyInContent(owningType, projectedProperties, propertyName, propertyValue, propertySourcePathSegment)) { if ((propertySourcePathSegment == null) || (complexValue == null)) { return(false); } emptyProjectedPropertiesMarker = ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker; } WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); if (propertyValue is ODataStreamReferenceValue) { throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } if (((edmProperty != null) && edmProperty.Type.IsSpatial()) || ((edmProperty == null) && (propertyValue is ISpatial))) { ODataVersionChecker.CheckSpatialValue(base.Version); } if (propertyValue == null) { this.WriteNullPropertyValue(edmProperty, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = ((owningType != null) && owningType.IsOpen) && (edmProperty == null); if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, propertyValue); } IEdmTypeReference metadataTypeReference = (edmProperty == null) ? null : edmProperty.Type; if (complexValue != null) { DuplicatePropertyNamesChecker checker = base.CreateDuplicatePropertyNamesChecker(); if (isTopLevel) { this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WriteComplexValue(complexValue, metadataTypeReference, isOpenPropertyType, isWritingCollection, null, null, checker, null, epmValueCache, propertySourcePathSegment, null); this.WritePropertyEnd(); return(true); } if (beforeValueAction == null) { beforeValueAction = delegate { this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); }; } if (afterValueAction == null) { afterValueAction = delegate { this.WritePropertyEnd(); }; } return(this.WriteComplexValue(complexValue, metadataTypeReference, isOpenPropertyType, isWritingCollection, beforeValueAction, afterValueAction, checker, null, epmValueCache, propertySourcePathSegment, emptyProjectedPropertiesMarker)); } ODataCollectionValue collectionValue = propertyValue as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(base.Version, propertyName); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WriteCollectionValue(collectionValue, metadataTypeReference, isOpenPropertyType, isWritingCollection); this.WritePropertyEnd(); return(true); } this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WritePrimitiveValue(propertyValue, null, metadataTypeReference); this.WritePropertyEnd(); return(true); }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The owning type for the <paramref name="property"/> or null if no metadata is available.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a top-level collection instead of an entry.</param> /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if the property was actually written, false otherwise.</returns> private bool WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); object value = property.Value; string propertyName = property.Name; //// TODO: If we implement type conversions the value needs to be converted here //// since the next method call needs to know if the value is a string or not in some cases. ODataComplexValue complexValue = value as ODataComplexValue; ProjectedPropertiesAnnotation complexValueProjectedProperties = null; if (!ShouldWritePropertyInContent(projectedProperties, propertyName)) { return false; } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (value is ODataStreamReferenceValue) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } // Null property value. if (value == null) { this.WriteNullPropertyValue(propertyTypeReference, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return true; } bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } if (complexValue != null) { return this.WriteComplexValueProperty( complexValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType, complexValueProjectedProperties); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionValueProperty( collectionValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType); return true; } // If the value isn't one of the value types tested for already, it must be a non-null primitive or enum type. this.WritePropertyStart(beforePropertyAction, property, isWritingCollection, isTopLevel); SerializationTypeNameAnnotation serializationTypeNameAnnotation = property.ODataValue.GetAnnotation<SerializationTypeNameAnnotation>(); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { this.WriteEnumValue(enumValue, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); } else { this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); } this.WritePropertyEnd(); return true; }
/// <summary> /// Reads the content of a properties in an element (complex value, m:properties, ...) /// </summary> /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param> /// <param name="properties">The list of properties to add properties to.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The element to read properties from. /// Post-Condition: XmlNodeType.Element - The element to read properties from if it is an empty element. /// XmlNodeType.EndElement - The end element of the element to read properties from. /// </remarks> private void ReadPropertiesImplementation(IEdmStructuredType structuredType, ReadOnlyEnumerable <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { Debug.Assert(properties != null, "properties != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertXmlCondition(XmlNodeType.Element); // Empty values are valid - they have no properties if (!this.XmlReader.IsEmptyElement) { // Read over the complex value element to its first child node (or end-element) this.XmlReader.ReadStartElement(); // WCF DS will skip over the rest of the complex value or entity properties if the first element in it is preceded with // a text node. Once the first element is found (no matter its namespace) then the non-element nodes // are ignored but skipped and the reading continues. // For ODataLib we should not do this and probably just ignore the text node even at the beginning (to be consistent). do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { // Found a property IEdmProperty edmProperty = null; bool isOpen = false; bool ignoreProperty = false; if (structuredType != null) { // Lookup the property in metadata edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty); if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation) { throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType)); } // If the property was not declared, it must be open. isOpen = edmProperty == null; } if (ignoreProperty) { this.XmlReader.Skip(); } 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); ODataProperty property = this.ReadProperty( false, edmProperty == null ? null : edmProperty.Name, edmProperty == null ? null : edmProperty.Type, nullValueReadBehaviorKind); Debug.Assert( property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue, "If we don't ignore null values the property must not be null."); if (property != null) { if (isOpen) { ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); properties.AddToSourceList(property); } } } else { this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // End of the complex value. break; default: // Non-element so for example a text node, just ignore this.XmlReader.Skip(); break; } }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } }
/// <summary> /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal. /// </summary> /// <param name="associationLink">The association link for which to write the metadata.</param> /// <param name="owningType">The <see cref="IEdmEntityType"/> instance the association link is defined on.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> internal void WriteAssociationLink( ODataAssociationLink associationLink, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); ValidationUtils.ValidateAssociationLinkNotNull(associationLink); if (projectedProperties.ShouldSkipProperty(associationLink.Name)) { return; } this.ValidateAssociationLink(associationLink, owningType); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(associationLink); AtomLinkMetadata linkMetadata = associationLink.GetAnnotation<AtomLinkMetadata>(); string linkRelation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink); AtomLinkMetadata mergedLinkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(linkMetadata, linkRelation, associationLink.Url, associationLink.Name, MimeConstants.MimeApplicationXml); this.atomEntryMetadataSerializer.WriteAtomLink(mergedLinkMetadata, null /* etag*/); }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName, bypassValidation); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); if (property.InstanceAnnotations.Any()) { if (isTopLevel) { this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations); } else { this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations, propertyName); } } IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined( propertyName, owningType, !this.bypassValidation); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; ODataValue value = property.ODataValue; ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.WritingResponse, this.bypassValidation); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName; if (value is ODataNullValue || value == null) { WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model, this.bypassValidation); if (isTopLevel) { // Write the special null marker for top-level null properties. this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNull); this.JsonWriter.WriteValue(true); } else { this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteNullValue(); } return; } bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty); if (isOpenPropertyType && this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { if (!isTopLevel) { this.JsonWriter.WriteName(wirePropertyName); } this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { // This is a work around, needTypeOnWire always = true for client side: // ClientEdmModel's reflection can't know a property is open type even if it is, so here // make client side always write 'odata.type' for enum. bool needTypeOnWire = string.Equals(this.JsonLightOutputContext.Model.GetType().Name, "ClientEdmModel", StringComparison.OrdinalIgnoreCase); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting( enumValue, propertyTypeReference, typeFromValue, needTypeOnWire ? true /* leverage this flag to write 'odata.type' */ : isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteEnumValue(enumValue, propertyTypeReference); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); // passing false for 'isTopLevel' because the outer wrapping object has already been written. this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType); } else { ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; Debug.Assert(primitiveValue != null, "primitiveValue != null"); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference); } }
/// <summary> /// Reads the content of a properties in an element (complex value, m:properties, ...) /// </summary> /// <param name="structuredType">The type which should declare the properties to be read. Optional.</param> /// <param name="properties">The list of properties to add properties to.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The element to read properties from. /// Post-Condition: XmlNodeType.Element - The element to read properties from if it is an empty element. /// XmlNodeType.EndElement - The end element of the element to read properties from. /// </remarks> private void ReadPropertiesImplementation(IEdmStructuredType structuredType, List <ODataProperty> properties, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { Debug.Assert(properties != null, "properties != null"); Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); this.AssertXmlCondition(XmlNodeType.Element); // Empty values are valid - they have no properties if (!this.XmlReader.IsEmptyElement) { // Read over the complex value element to its first child node (or end-element) this.XmlReader.ReadStartElement(); do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { // Found a property IEdmProperty edmProperty = null; bool isOpen = false; bool ignoreProperty = false; if (structuredType != null) { // Lookup the property in metadata edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(this.XmlReader.LocalName, structuredType, this.MessageReaderSettings, out ignoreProperty); if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Navigation) { throw new ODataException(o.Strings.ODataAtomPropertyAndValueDeserializer_NavigationPropertyInProperties(edmProperty.Name, structuredType)); } // If the property was not declared, it must be open. isOpen = edmProperty == null; } if (ignoreProperty) { this.XmlReader.Skip(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); ODataProperty property = this.ReadProperty(edmProperty == null ? null : edmProperty.Type, nullValueReadBehaviorKind, epmPresent); Debug.Assert( property != null || nullValueReadBehaviorKind == ODataNullValueBehaviorKind.IgnoreValue, "If we don't ignore null values the property must not be null."); if (property != null) { if (isOpen) { ValidationUtils.ValidateOpenPropertyValue(property.Name, property.Value); } duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); properties.Add(property); } } } else { this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // End of the complex value. break; default: // Non-element so for example a text node, just ignore this.XmlReader.Skip(); break; } }while (this.XmlReader.NodeType != XmlNodeType.EndElement); } }