/// <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 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 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); }