private void WriteEntryContent(ODataEntry entry, IEdmEntityType entryType, EntryPropertiesValueCache propertiesValueCache, EpmSourcePathSegment rootSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource == null) { this.atomOutputContext.XmlWriter.WriteStartElement("", "content", "http://www.w3.org/2005/Atom"); this.atomOutputContext.XmlWriter.WriteAttributeString("type", "application/xml"); this.atomEntryAndFeedSerializer.WriteProperties(entryType, propertiesValueCache.EntryProperties, false, new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart), new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd), base.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomOutputContext.XmlWriter.WriteEndElement(); } else { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.atomEntryAndFeedSerializer.WriteEntryMediaEditLink(mediaResource); if (mediaResource.ReadLink != null) { this.atomOutputContext.XmlWriter.WriteStartElement("", "content", "http://www.w3.org/2005/Atom"); this.atomOutputContext.XmlWriter.WriteAttributeString("type", mediaResource.ContentType); this.atomOutputContext.XmlWriter.WriteAttributeString("src", this.atomEntryAndFeedSerializer.UriToUrlAttributeValue(mediaResource.ReadLink)); this.atomOutputContext.XmlWriter.WriteEndElement(); } this.atomEntryAndFeedSerializer.WriteProperties(entryType, propertiesValueCache.EntryProperties, false, new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart), new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd), base.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); } }
/// <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); } }
/// <summary> /// Writes the __metadata property and its content for an entry /// </summary> /// <param name="entry">The entry for which to write the metadata.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <param name="entryEntityType">The entity type of the entry to write.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> internal void WriteEntryMetadata( ODataEntry entry, ProjectedPropertiesAnnotation projectedProperties, IEdmEntityType entryEntityType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entry != null, "entry != null"); // Write the "__metadata" for the entry this.JsonWriter.WriteName(JsonConstants.ODataMetadataName); this.JsonWriter.StartObjectScope(); // Write the "id": "Entity Id" string id = entry.Id; if (id != null) { this.JsonWriter.WriteName(JsonConstants.ODataEntryIdName); this.JsonWriter.WriteValue(id); } // Write the "uri": "edit/read-link-uri" Uri uriValue = entry.EditLink ?? entry.ReadLink; if (uriValue != null) { this.JsonWriter.WriteName(JsonConstants.ODataMetadataUriName); this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(uriValue)); } // Write the "etag": "ETag value" // TODO: if this is a top-level entry also put the ETag into the headers. string etag = entry.ETag; if (etag != null) { this.WriteETag(JsonConstants.ODataMetadataETagName, etag); } // Write the "type": "typename" string typeName = this.VerboseJsonOutputContext.TypeNameOracle.GetEntryTypeNameForWriting(entry); if (typeName != null) { this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.JsonWriter.WriteValue(typeName); } // Write MLE metadata ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource != null) { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.WriteStreamReferenceValueContent(mediaResource); } // write "actions" metadata IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { this.WriteOperations(actions.Cast <ODataOperation>(), JsonConstants.ODataActionsMetadataName, /*isAction*/ true, /*writingJsonLight*/ false); } // write "functions" metadata IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { this.WriteOperations(functions.Cast <ODataOperation>(), JsonConstants.ODataFunctionsMetadataName, /*isAction*/ false, /*writingJsonLight*/ false); } // Write properties metadata // For now only association links are supported here IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { bool firstAssociationLink = true; foreach (ODataAssociationLink associationLink in associationLinks) { ValidationUtils.ValidateAssociationLinkNotNull(associationLink); if (projectedProperties.ShouldSkipProperty(associationLink.Name)) { continue; } if (firstAssociationLink) { // Write the "properties": { this.JsonWriter.WriteName(JsonConstants.ODataMetadataPropertiesName); this.JsonWriter.StartObjectScope(); firstAssociationLink = false; } this.ValidateAssociationLink(associationLink, entryEntityType); this.WriteAssociationLink(associationLink, duplicatePropertyNamesChecker); } if (!firstAssociationLink) { // Close the "properties" object this.JsonWriter.EndObjectScope(); } } // Close the __metadata object scope this.JsonWriter.EndObjectScope(); }
/// <summary> /// Write the content of the given entry. /// </summary> /// <param name="entry">The entry for which to write properties.</param> /// <param name="entryType">The <see cref="IEdmEntityType"/> of the entry (or null if not metadata is available).</param> /// <param name="propertiesValueCache">The cache of properties.</param> /// <param name="rootSourcePathSegment">The root of the EPM source tree, if there's an EPM applied.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> private void WriteEntryContent( ODataEntry entry, IEdmEntityType entryType, EntryPropertiesValueCache propertiesValueCache, EpmSourcePathSegment rootSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(propertiesValueCache != null, "propertiesValueCache != null"); ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource == null) { // <content type="application/xml"> this.atomOutputContext.XmlWriter.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.AtomTypeAttributeName, MimeConstants.MimeApplicationXml); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); this.atomEntryAndFeedSerializer.WriteProperties( entryType, propertiesValueCache.EntryProperties, false /* isWritingCollection */, this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart, this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd, this.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); // </content> this.atomOutputContext.XmlWriter.WriteEndElement(); } else { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.atomEntryAndFeedSerializer.WriteEntryMediaEditLink(mediaResource); if (mediaResource.ReadLink != null) { // <content type="type" src="src"> this.atomOutputContext.XmlWriter.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); Debug.Assert(!string.IsNullOrEmpty(mediaResource.ContentType), "The default stream content type should have been validated by now. If we have a read link we must have a non-empty content type as well."); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.AtomTypeAttributeName, mediaResource.ContentType); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.MediaLinkEntryContentSourceAttributeName, this.atomEntryAndFeedSerializer.UriToUrlAttributeValue(mediaResource.ReadLink)); // </content> this.atomOutputContext.XmlWriter.WriteEndElement(); } this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); this.atomEntryAndFeedSerializer.WriteProperties( entryType, propertiesValueCache.EntryProperties, false /* isWritingCollection */, this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart, this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd, this.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); } }
internal void WriteEntryMetadata(ODataEntry entry, ProjectedPropertiesAnnotation projectedProperties, IEdmEntityType entryEntityType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { base.JsonWriter.WriteName("__metadata"); base.JsonWriter.StartObjectScope(); string id = entry.Id; if (id != null) { base.JsonWriter.WriteName("id"); base.JsonWriter.WriteValue(id); } Uri uri = entry.EditLink ?? entry.ReadLink; if (uri != null) { base.JsonWriter.WriteName("uri"); base.JsonWriter.WriteValue(base.UriToAbsoluteUriString(uri)); } string eTag = entry.ETag; if (eTag != null) { base.WriteETag("etag", eTag); } string typeName = entry.TypeName; SerializationTypeNameAnnotation annotation = entry.GetAnnotation <SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } if (typeName != null) { base.JsonWriter.WriteName("type"); base.JsonWriter.WriteValue(typeName); } ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource != null) { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); base.WriteStreamReferenceValueContent(mediaResource); } IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { this.WriteOperations(actions.Cast <ODataOperation>(), true); } IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { this.WriteOperations(functions.Cast <ODataOperation>(), false); } IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { bool flag = true; foreach (ODataAssociationLink link in associationLinks) { ValidationUtils.ValidateAssociationLinkNotNull(link); if (!projectedProperties.ShouldSkipProperty(link.Name)) { if (flag) { base.JsonWriter.WriteName("properties"); base.JsonWriter.StartObjectScope(); flag = false; } base.ValidateAssociationLink(link, entryEntityType); this.WriteAssociationLink(link, duplicatePropertyNamesChecker); } } if (!flag) { base.JsonWriter.EndObjectScope(); } } base.JsonWriter.EndObjectScope(); }
/// <summary> /// Writes a name/value pair for a property. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry or complex type containing the property (or null if not 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); string propertyName = property.Name; object value = property.Value; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; // 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); } this.JsonWriter.WriteName(propertyName); if (value == null) { WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model); this.JsonWriter.WriteValue(null); } else { bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); } 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, propertyName); this.WriteCollectionValue( collectionValue, propertyTypeReference, isOpenPropertyType); } else { 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."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse); WriterValidationUtils.ValidateStreamReferenceValue(streamReferenceValue, /*isDefaultStream*/ false); this.WriteStreamReferenceValue(streamReferenceValue); } else { this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference); } } } } }