private bool ShouldWritePropertyInContent(IEdmStructuredType owningType, ProjectedPropertiesAnnotation projectedProperties, string propertyName, object propertyValue, EpmSourcePathSegment epmSourcePathSegment) { bool flag = !projectedProperties.ShouldSkipProperty(propertyName); if ((((base.MessageWriterSettings.WriterBehavior != null) && base.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior) && (owningType != null)) && owningType.IsODataComplexTypeKind()) { IEdmComplexType complexType = (IEdmComplexType) owningType; CachedPrimitiveKeepInContentAnnotation annotation = base.Model.EpmCachedKeepPrimitiveInContent(complexType); if ((annotation != null) && annotation.IsKeptInContent(propertyName)) { return flag; } } if ((propertyValue == null) && (epmSourcePathSegment != null)) { return true; } EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment); if (entityPropertyMapping == null) { return flag; } string str = propertyValue as string; if ((str != null) && (str.Length == 0)) { switch (entityPropertyMapping.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorEmail: case SyndicationItemProperty.ContributorUri: return true; } } return (entityPropertyMapping.KeepInContent && flag); }
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); } }
private void EnterScope(WriterState newState, ODataItem item) { this.InterceptException(() => this.ValidateTransition(newState)); bool skipWriting = this.SkipWriting; Scope currentScope = this.CurrentScope; if (((currentScope.State == WriterState.Entry) && (newState == WriterState.NavigationLink)) && !skipWriting) { ProjectedPropertiesAnnotation projectedProperties = currentScope.Item.GetAnnotation <ProjectedPropertiesAnnotation>(); ODataNavigationLink link = (ODataNavigationLink)item; skipWriting = projectedProperties.ShouldSkipProperty(link.Name); } else if ((currentScope.State == WriterState.Feed) && (newState == WriterState.Entry)) { FeedScope scope1 = (FeedScope)currentScope; scope1.EntryCount++; } this.PushScope(newState, item, skipWriting); }
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); } }
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); } } } } }
internal void WriteProperties(IEdmStructuredType owningType, IEnumerable<ODataProperty> properties, bool isComplexValue, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { if (properties != null) { foreach (ODataProperty property in properties) { this.WriteProperty(property, owningType, !isComplexValue, duplicatePropertyNamesChecker, projectedProperties); } } }
/// <summary> /// Writes property names and value pairs. /// </summary> /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry (or null if not metadata is available).</param> /// <param name="properties">The enumeration of properties to write out.</param> /// <param name="isComplexValue"> /// Whether the properties are being written for complex value. Also used for detecting whether stream properties /// are allowed as 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> internal void WriteProperties( IEdmStructuredType owningType, IEnumerable<ODataProperty> properties, bool isComplexValue, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); if (properties == null) { return; } foreach (ODataProperty property in properties) { this.WriteProperty( property, owningType, !isComplexValue, duplicatePropertyNamesChecker, projectedProperties); } }
/// <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 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 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; }
internal bool WriteProperties(IEdmStructuredType owningType, IEnumerable<ODataProperty> cachedProperties, bool isWritingCollection, Action beforePropertiesAction, Action afterPropertiesAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { if (cachedProperties == null) { return false; } bool flag = false; foreach (ODataProperty property in cachedProperties) { flag |= this.WriteProperty(property, owningType, false, isWritingCollection, flag ? null : beforePropertiesAction, epmValueCache, epmSourcePathSegment, duplicatePropertyNamesChecker, projectedProperties); } if ((afterPropertiesAction != null) && flag) { afterPropertiesAction(); } return flag; }
internal bool WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { Action action2 = null; string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } this.IncreaseRecursionDepth(); IEdmComplexTypeReference reference = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)) { typeName = null; } SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } Action beforePropertiesAction = beforeValueAction; if (typeName != null) { if (beforeValueAction != null) { if (action2 == null) { action2 = delegate { beforeValueAction(); this.WritePropertyTypeAttribute(typeName); }; } beforePropertiesAction = action2; } else { this.WritePropertyTypeAttribute(typeName); } } if (((base.MessageWriterSettings.WriterBehavior != null) && base.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior) && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker)) { IEdmComplexType definition = (IEdmComplexType) reference.Definition; if (base.Model.EpmCachedKeepPrimitiveInContent(definition) == null) { List<string> keptInContentPropertyNames = null; foreach (IEdmProperty property in from p in definition.Properties() where p.Type.IsODataPrimitiveTypeKind() select p) { EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, property.Name); if ((entityPropertyMapping != null) && entityPropertyMapping.KeepInContent) { if (keptInContentPropertyNames == null) { keptInContentPropertyNames = new List<string>(); } keptInContentPropertyNames.Add(property.Name); } } base.Model.SetAnnotationValue<CachedPrimitiveKeepInContentAnnotation>(definition, new CachedPrimitiveKeepInContentAnnotation(keptInContentPropertyNames)); } } bool flag = this.WriteProperties((reference == null) ? null : reference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforePropertiesAction, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties); this.DecreaseRecursionDepth(); return flag; }
/// <summary> /// Write the given collection of properties. /// </summary> /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the entry (or null if not metadata is available).</param> /// <param name="cachedProperties">Collection of cached properties for the entry.</param> /// <param name="isWritingCollection">true if we are writing a collection instead of an entry.</param> /// <param name="beforePropertiesAction">Action which is called before the properties are written, if there are any property.</param> /// <param name="afterPropertiesAction">Action which is called after the properties are written, if there are any property.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</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="epmSourcePathSegment">The EPM source path segment which points to the property which sub-properites we're writing. (can be null)</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if anything was written, false otherwise.</returns> internal bool WriteProperties( IEdmStructuredType owningType, IEnumerable<ODataProperty> cachedProperties, bool isWritingCollection, Action beforePropertiesAction, Action afterPropertiesAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); if (cachedProperties == null) { return false; } bool propertyWritten = false; foreach (ODataProperty property in cachedProperties) { propertyWritten |= this.WriteProperty( property, owningType, false, isWritingCollection, propertyWritten ? null : beforePropertiesAction, epmValueCache, epmSourcePathSegment, duplicatePropertyNamesChecker, projectedProperties); } if (afterPropertiesAction != null && propertyWritten) { afterPropertiesAction(); } return propertyWritten; }
/// <summary> /// Determines if the property with the specified value should be written into content or not. /// </summary> /// <param name="owningType">The owning type of the property to be checked.</param> /// <param name="projectedProperties">The set of projected properties for the <paramref name="owningType"/></param> /// <param name="propertyName">The name of the property to be checked.</param> /// <param name="propertyValue">The property value to write.</param> /// <param name="epmSourcePathSegment">The EPM source path segment for the property being written.</param> /// <returns>true if the property should be written into content, or false otherwise</returns> private bool ShouldWritePropertyInContent( IEdmStructuredType owningType, ProjectedPropertiesAnnotation projectedProperties, string propertyName, object propertyValue, EpmSourcePathSegment epmSourcePathSegment) { // check whether the property is projected; if no EPM is specified for the property the projection decides bool propertyProjected = !projectedProperties.ShouldSkipProperty(propertyName); bool useV1ProviderBehavior = this.MessageWriterSettings.WriterBehavior == null ? false : this.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior; if (useV1ProviderBehavior && owningType != null && owningType.IsODataComplexTypeKind()) { IEdmComplexType owningComplexType = (IEdmComplexType)owningType; CachedPrimitiveKeepInContentAnnotation keepInContentAnnotation = this.Model.EpmCachedKeepPrimitiveInContent(owningComplexType); if (keepInContentAnnotation != null && keepInContentAnnotation.IsKeptInContent(propertyName)) { return propertyProjected; } } // We sometimes write properties into content even if asked not to. // If the property value is null and the property (or one of its descendant properties) is mapped, // we always write into content, even if the property was not projected. if (propertyValue == null && epmSourcePathSegment != null) { return true; } EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment); if (entityPropertyMapping == null) { return propertyProjected; } string stringPropertyValue = propertyValue as string; if (stringPropertyValue != null && stringPropertyValue.Length == 0) { // If the property value is an empty string and we should be writing it into an ATOM element which does not allow empty string // we write it into content as well, also even if the property was not projected. switch (entityPropertyMapping.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: case SyndicationItemProperty.AuthorUri: case SyndicationItemProperty.ContributorEmail: case SyndicationItemProperty.ContributorUri: return true; default: break; } } return entityPropertyMapping.KeepInContent && propertyProjected; }
/// <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 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); } } }
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(); }
internal static bool ShouldSkipProperty(this ProjectedPropertiesAnnotation projectedProperties, string propertyName) { return((projectedProperties != null) && !projectedProperties.IsPropertyProjected(propertyName)); }
internal bool WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } this.IncreaseRecursionDepth(); // resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata IEdmComplexTypeReference complexTypeReference = WriterValidationUtils.ResolveTypeNameForWriting(this.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed. if (typeName != null && collectionValidator != null) { string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection; if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0) { typeName = null; } } SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation<SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { typeName = serializationTypeNameAnnotation.TypeName; } Action beforeValueCallbackWithTypeName = beforeValueAction; if (typeName != null) { // The beforeValueAction (if specified) will write the actual property element start. // So if we are to write the type attribute, we must postpone that after the start element was written. // And so we chain the existing action with our type attribute writing and use that // as the before action instead. if (beforeValueAction != null) { beforeValueCallbackWithTypeName = () => { beforeValueAction(); this.WritePropertyTypeAttribute(typeName); }; } else { this.WritePropertyTypeAttribute(typeName); } } // NOTE: see the comments on ODataWriterBehavior.UseV1ProviderBehavior for more information // NOTE: We have to check for ProjectedPropertiesAnnotation.Empty here to avoid filling the cache for // complex values we are writing only to ensure we don't have nested EPM-mapped null values // that will end up in the content eventually. if (this.MessageWriterSettings.WriterBehavior != null && this.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker)) { IEdmComplexType complexType = (IEdmComplexType)complexTypeReference.Definition; CachedPrimitiveKeepInContentAnnotation keepInContentCache = this.Model.EpmCachedKeepPrimitiveInContent(complexType); if (keepInContentCache == null) { // we are about to write the first value of the given type; compute the keep-in-content information for the primitive properties of this type. List<string> keepInContentPrimitiveProperties = null; // initialize the cache with all primitive properties foreach (IEdmProperty edmProperty in complexType.Properties().Where(p => p.Type.IsODataPrimitiveTypeKind())) { // figure out the keep-in-content value EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, edmProperty.Name); if (entityPropertyMapping != null && entityPropertyMapping.KeepInContent) { if (keepInContentPrimitiveProperties == null) { keepInContentPrimitiveProperties = new List<string>(); } keepInContentPrimitiveProperties.Add(edmProperty.Name); } } this.Model.SetAnnotationValue<CachedPrimitiveKeepInContentAnnotation>(complexType, new CachedPrimitiveKeepInContentAnnotation(keepInContentPrimitiveProperties)); } } bool propertyWritten = this.WriteProperties( complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforeValueCallbackWithTypeName, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties); this.DecreaseRecursionDepth(); return propertyWritten; }