private static string CreateDateTimeStringValue(object propertyValue, ODataWriterBehavior writerBehavior) { Debug.Assert( writerBehavior.FormatBehaviorKind == ODataBehaviorKind.WcfDataServicesClient, "CreateDateTimeStringValue should only be used in WCF DS client mode."); if (propertyValue == null) { propertyValue = DateTimeOffset.Now; } if (propertyValue is DateTime) { // DateTimeOffset takes care of DateTimes of Unspecified kind so we won't end up // with datetime without timezone info mapped to atom:updated or atom:published element. propertyValue = new DateTimeOffset((DateTime)propertyValue); } // For DateTimeOffset values we need to use the ATOM format when translating them // to strings since the value will be used in ATOM metadata. if (propertyValue is DateTimeOffset) { return(ODataAtomConvert.ToAtomString((DateTimeOffset)propertyValue)); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
/// <summary> /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM. /// </summary> /// <param name="targetSegment">The target segment to read the value for.</param> /// <param name="epmValueCache">EPM value cache to use to get property values, or a primitive value</param> /// <param name="typeReference">The type of the entry or collection item.</param> /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns> private string GetPropertyValueAsText( EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content."); Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property."); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(typeReference != null, "typeReference != null"); object propertyValue; EntryPropertiesValueCache entryPropertiesValueCache = epmValueCache as EntryPropertiesValueCache; if (entryPropertiesValueCache != null) { propertyValue = this.ReadEntryPropertyValue( targetSegment.EpmInfo, entryPropertiesValueCache, typeReference.AsEntity()); } else { propertyValue = epmValueCache; ValidationUtils.ValidateIsExpectedPrimitiveType(propertyValue, typeReference); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
/// <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); }
private string GetEntryPropertyValueAsText(EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { object propertyValue = base.ReadEntryPropertyValue(targetSegment.EpmInfo, epmValueCache, entityType); if (propertyValue == null) { return(string.Empty); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
private static string CreateDateTimeStringValue(object propertyValue, ODataWriterBehavior writerBehavior) { if (propertyValue == null) { propertyValue = DateTimeOffset.Now; } if (propertyValue is DateTime) { propertyValue = new DateTimeOffset((DateTime)propertyValue); } if (propertyValue is DateTimeOffset) { return(ODataAtomConvert.ToAtomString((DateTimeOffset)propertyValue)); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
private string GetPropertyValueAsText(EpmTargetPathSegment targetSegment, object epmValueCache, IEdmTypeReference typeReference) { object obj2; EntryPropertiesValueCache cache = epmValueCache as EntryPropertiesValueCache; if (cache != null) { obj2 = base.ReadEntryPropertyValue(targetSegment.EpmInfo, cache, typeReference.AsEntity()); } else { obj2 = epmValueCache; ValidationUtils.ValidateIsExpectedPrimitiveType(obj2, typeReference); } return(EpmWriterUtils.GetPropertyValueAsText(obj2)); }
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); }
/// <summary> /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM. /// </summary> /// <param name="targetSegment">The target segment to read the value for.</param> /// <param name="epmValueCache">The entry EPM value cache to use.</param> /// <param name="entityType">The entity type of the entry being processed.</param> /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns> private string GetEntryPropertyValueAsText( EpmTargetPathSegment targetSegment, EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { Debug.Assert(targetSegment != null, "targetSegment != null"); Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content."); Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property."); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(entityType != null, "entityType != null"); object propertyValue = this.ReadEntryPropertyValue( targetSegment.EpmInfo, epmValueCache, entityType); if (propertyValue == null) { // nulls are written out as empty strings always (and they're written into content as well) return(string.Empty); } return(EpmWriterUtils.GetPropertyValueAsText(propertyValue)); }
/// <summary> /// Writes the syndication part of EPM for an entry into ATOM metadata OM. /// </summary> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="entityType">The type of the entry.</param> /// <returns>The ATOM metadata OM with the EPM values populated.</returns> private AtomEntryMetadata WriteEntryEpm( EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = this.epmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return(null); } foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the EPM attribute"); object propertyValue = this.ReadEntryPropertyValue( epmInfo, epmValueCache, entityType); string textPropertyValue = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: if (this.WriterBehavior.FormatBehaviorKind == ODataBehaviorKind.WcfDataServicesClient) { this.entryMetadata.UpdatedString = EpmSyndicationWriter.CreateDateTimeStringValue(propertyValue, this.WriterBehavior); } else { this.entryMetadata.Updated = EpmSyndicationWriter.CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, this.WriterBehavior); } break; case SyndicationItemProperty.Published: if (this.WriterBehavior.FormatBehaviorKind == ODataBehaviorKind.WcfDataServicesClient) { this.entryMetadata.PublishedString = EpmSyndicationWriter.CreateDateTimeStringValue(propertyValue, this.WriterBehavior); } else { this.entryMetadata.Published = EpmSyndicationWriter.CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, this.WriterBehavior); } break; case SyndicationItemProperty.Rights: this.entryMetadata.Rights = EpmSyndicationWriter.CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind); break; case SyndicationItemProperty.Summary: this.entryMetadata.Summary = EpmSyndicationWriter.CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind); break; case SyndicationItemProperty.Title: this.entryMetadata.Title = EpmSyndicationWriter.CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind); break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } } else { this.WriteParentSegment(targetSegment, epmValueCache, entityType); } } return(this.entryMetadata); }
protected override void EndEntry(ODataEntry entry) { if (entry == null) { this.CheckAndWriteParentNavigationLinkEndForInlineElement(); } else { IEdmEntityType entryEntityType = base.EntryEntityType; EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry); ODataEntityPropertyMappingCache cache2 = this.atomOutputContext.Model.EnsureEpmCache(entryEntityType, 0x7fffffff); if (cache2 != null) { EpmWriterUtils.CacheEpmProperties(propertyValueCache, cache2.EpmSourceTree); } ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>(); AtomEntryScope currentEntryScope = this.CurrentEntryScope; AtomEntryMetadata entryMetadata = entry.Atom(); if (!currentEntryScope.IsElementWritten(AtomElement.Id)) { this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id); } Uri editLink = entry.EditLink; if ((editLink != null) && !currentEntryScope.IsElementWritten(AtomElement.EditLink)) { this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata); } Uri readLink = entry.ReadLink; if ((readLink != null) && !currentEntryScope.IsElementWritten(AtomElement.ReadLink)) { this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata); } AtomEntryMetadata epmEntryMetadata = null; if (cache2 != null) { ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryEntityType, this.atomOutputContext.Model); epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm(cache2.EpmTargetTree, propertyValueCache, entryEntityType.ToTypeReference().AsEntity(), this.atomOutputContext); } this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime); IEnumerable <ODataProperty> entryStreamProperties = propertyValueCache.EntryStreamProperties; if (entryStreamProperties != null) { foreach (ODataProperty property in entryStreamProperties) { this.atomEntryAndFeedSerializer.WriteStreamProperty(property, entryEntityType, base.DuplicatePropertyNamesChecker, projectedProperties); } } IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { foreach (ODataAssociationLink link in associationLinks) { this.atomEntryAndFeedSerializer.WriteAssociationLink(link, entryEntityType, base.DuplicatePropertyNamesChecker, projectedProperties); } } IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { foreach (ODataAction action in actions) { ValidationUtils.ValidateOperationNotNull(action, true); this.atomEntryAndFeedSerializer.WriteOperation(action); } } IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { foreach (ODataFunction function in functions) { ValidationUtils.ValidateOperationNotNull(function, false); this.atomEntryAndFeedSerializer.WriteOperation(function); } } this.WriteEntryContent(entry, entryEntityType, propertyValueCache, (cache2 == null) ? null : cache2.EpmSourceTree.Root, projectedProperties); if (cache2 != null) { EpmCustomWriter.WriteEntryEpm(this.atomOutputContext.XmlWriter, cache2.EpmTargetTree, propertyValueCache, entryEntityType.ToTypeReference().AsEntity(), this.atomOutputContext); } this.atomOutputContext.XmlWriter.WriteEndElement(); this.EndEntryXmlCustomization(entry); this.CheckAndWriteParentNavigationLinkEndForInlineElement(); } }
protected override void EndEntry(ODataEntry entry) { Debug.Assert( this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value, "We should have already verified that the IsCollection matches the actual content of the link (feed/entry)."); if (entry == null) { Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation."); // this is a null expanded single entry and it is null, an empty <m:inline /> will be written. this.CheckAndWriteParentNavigationLinkEndForInlineElement(); return; } IEdmEntityType entryType = this.EntryEntityType; // Initialize the property value cache and cache the entry properties. EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry); // NOTE: when writing, we assume the model has been validated already and thus pass int.MaxValue for the maxMappingCount. ODataEntityPropertyMappingCache epmCache = this.atomOutputContext.Model.EnsureEpmCache(entryType, /*maxMappingCount*/ int.MaxValue); // Populate the property value cache based on the EPM source tree information. // We do this since we need to write custom EPM after the properties below and don't // want to cache all properties just for the case that they are used in a custom EPM. if (epmCache != null) { EpmWriterUtils.CacheEpmProperties(propertyValueCache, epmCache.EpmSourceTree); } // Get the projected properties annotation ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>(); AtomEntryScope currentEntryScope = this.CurrentEntryScope; AtomEntryMetadata entryMetadata = entry.Atom(); if (!currentEntryScope.IsElementWritten(AtomElement.Id)) { // NOTE: We write even null id, in that case we generate an empty atom:id element. this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id); } Uri editLink = entry.EditLink; if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink)) { this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata); } Uri readLink = entry.ReadLink; if (readLink != null && !currentEntryScope.IsElementWritten(AtomElement.ReadLink)) { this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata); } // write entry metadata including syndication EPM AtomEntryMetadata epmEntryMetadata = null; if (epmCache != null) { ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryType, this.atomOutputContext.Model); epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm( epmCache.EpmTargetTree, propertyValueCache, entryType.ToTypeReference().AsEntity(), this.atomOutputContext); } this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime); // stream properties IEnumerable <ODataProperty> streamProperties = propertyValueCache.EntryStreamProperties; if (streamProperties != null) { foreach (ODataProperty streamProperty in streamProperties) { this.atomEntryAndFeedSerializer.WriteStreamProperty( streamProperty, entryType, this.DuplicatePropertyNamesChecker, projectedProperties); } } // association links IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { foreach (ODataAssociationLink associationLink in associationLinks) { this.atomEntryAndFeedSerializer.WriteAssociationLink( associationLink, entryType, this.DuplicatePropertyNamesChecker, projectedProperties); } } // actions IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { foreach (ODataAction action in actions) { ValidationUtils.ValidateOperationNotNull(action, true); this.atomEntryAndFeedSerializer.WriteOperation(action); } } // functions IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { foreach (ODataFunction function in functions) { ValidationUtils.ValidateOperationNotNull(function, false); this.atomEntryAndFeedSerializer.WriteOperation(function); } } // write the content this.WriteEntryContent( entry, entryType, propertyValueCache, epmCache == null ? null : epmCache.EpmSourceTree.Root, projectedProperties); // write custom EPM if (epmCache != null) { EpmCustomWriter.WriteEntryEpm( this.atomOutputContext.XmlWriter, epmCache.EpmTargetTree, propertyValueCache, entryType.ToTypeReference().AsEntity(), this.atomOutputContext); } // </entry> this.atomOutputContext.XmlWriter.WriteEndElement(); this.EndEntryXmlCustomization(entry); this.CheckAndWriteParentNavigationLinkEndForInlineElement(); }
/// <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); }
/// <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); }
internal bool WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } this.IncreaseRecursionDepth(); // resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata IEdmComplexTypeReference complexTypeReference = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType).AsComplexOrNull(); string collectionItemTypeName; typeName = this.AtomOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexTypeReference, complexValue.GetAnnotation <SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName); Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null"); Action beforeValueCallbackWithTypeName = beforeValueAction; if (typeName != null) { // The beforeValueAction (if specified) will write the actual property element start. // So if we are to write the type attribute, we must postpone that after the start element was written. // And so we chain the existing action with our type attribute writing and use that // as the before action instead. if (beforeValueAction != null) { beforeValueCallbackWithTypeName = () => { beforeValueAction(); this.WritePropertyTypeAttribute(typeName); }; } else { this.WritePropertyTypeAttribute(typeName); } } // NOTE: see the comments on ODataWriterBehavior.UseV1ProviderBehavior for more information // NOTE: We have to check for ProjectedPropertiesAnnotation.Empty here to avoid filling the cache for // complex values we are writing only to ensure we don't have nested EPM-mapped null values // that will end up in the content eventually. if (this.MessageWriterSettings.WriterBehavior != null && this.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesInstance)) { IEdmComplexType complexType = (IEdmComplexType)complexTypeReference.Definition; CachedPrimitiveKeepInContentAnnotation keepInContentCache = this.Model.EpmCachedKeepPrimitiveInContent(complexType); if (keepInContentCache == null) { // we are about to write the first value of the given type; compute the keep-in-content information for the primitive properties of this type. List <string> keepInContentPrimitiveProperties = null; // initialize the cache with all primitive properties foreach (IEdmProperty edmProperty in complexType.Properties().Where(p => p.Type.IsODataPrimitiveTypeKind())) { // figure out the keep-in-content value EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, edmProperty.Name); if (entityPropertyMapping != null && entityPropertyMapping.KeepInContent) { if (keepInContentPrimitiveProperties == null) { keepInContentPrimitiveProperties = new List <string>(); } keepInContentPrimitiveProperties.Add(edmProperty.Name); } } this.Model.SetAnnotationValue <CachedPrimitiveKeepInContentAnnotation>(complexType, new CachedPrimitiveKeepInContentAnnotation(keepInContentPrimitiveProperties)); } } bool propertyWritten = this.WriteProperties( complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforeValueCallbackWithTypeName, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties); this.DecreaseRecursionDepth(); return(propertyWritten); }
private AtomEntryMetadata WriteEntryEpm(EntryPropertiesValueCache epmValueCache, IEdmEntityTypeReference entityType) { EpmTargetPathSegment syndicationRoot = this.epmTargetTree.SyndicationRoot; if (syndicationRoot.SubSegments.Count == 0) { return(null); } foreach (EpmTargetPathSegment segment2 in syndicationRoot.SubSegments) { if (!segment2.HasContent) { goto Label_018C; } EntityPropertyMappingInfo epmInfo = segment2.EpmInfo; object propertyValue = base.ReadEntryPropertyValue(epmInfo, epmValueCache, entityType); string propertyValueAsText = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: { if (base.WriterBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesClient) { break; } this.entryMetadata.UpdatedString = CreateDateTimeStringValue(propertyValue, base.WriterBehavior); continue; } case SyndicationItemProperty.Published: { if (base.WriterBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesClient) { goto Label_00FE; } this.entryMetadata.PublishedString = CreateDateTimeStringValue(propertyValue, base.WriterBehavior); continue; } case SyndicationItemProperty.Rights: { this.entryMetadata.Rights = CreateAtomTextConstruct(propertyValueAsText, epmInfo.Attribute.TargetTextContentKind); continue; } case SyndicationItemProperty.Summary: { this.entryMetadata.Summary = CreateAtomTextConstruct(propertyValueAsText, epmInfo.Attribute.TargetTextContentKind); continue; } case SyndicationItemProperty.Title: { this.entryMetadata.Title = CreateAtomTextConstruct(propertyValueAsText, epmInfo.Attribute.TargetTextContentKind); continue; } default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } this.entryMetadata.Updated = new DateTimeOffset?(CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, base.WriterBehavior)); continue; Label_00FE: this.entryMetadata.Published = new DateTimeOffset?(CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, base.WriterBehavior)); continue; Label_018C: this.WriteParentSegment(segment2, epmValueCache, entityType); } return(this.entryMetadata); }
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 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); }