示例#1
0
        /// <summary>
        /// Cache the property and collection item enumerations needed in EPM mappings. We do this for syndication and custom
        /// mappings.
        /// </summary>
        /// <param name="valueCache">The property value cache to use for caching.</param>
        /// <param name="segments">The source path segments to cache.</param>
        /// <param name="properties">The <see cref="ODataProperty"/> values to compute the segments against.</param>
        private static void CacheEpmSourcePathSegments(EpmValueCache valueCache, List <EpmSourcePathSegment> segments, IEnumerable <ODataProperty> properties)
        {
            Debug.Assert(valueCache != null, "valueCache != null");
            Debug.Assert(segments != null, "segments != null");

            if (properties == null)
            {
                return;
            }

            foreach (EpmSourcePathSegment segment in segments)
            {
                if (segment.EpmInfo == null)
                {
                    // No EPM info means that this is a complex value (cannot be mapped directly); cache it.
                    ODataComplexValue complexValue;
                    if (TryGetPropertyValue <ODataComplexValue>(properties, segment.PropertyName, out complexValue))
                    {
                        // Cache the properties of the complex property
                        IEnumerable <ODataProperty> subProperties = valueCache.CacheComplexValueProperties(complexValue);
                        CacheEpmSourcePathSegments(valueCache, segment.SubProperties, subProperties);
                    }
                }
                else
                {
                    // Primitive collection item inside a complex value; nothing to do - we cached the property values already.
                    Debug.Assert(segment.SubProperties.Count == 0, "No sub-segments expected.");
                }
            }
        }
示例#2
0
 internal static IEnumerable<ODataProperty> GetComplexValueProperties(EpmValueCache epmValueCache, ODataComplexValue complexValue, bool writingContent)
 {
     if (epmValueCache == null)
     {
         return complexValue.Properties;
     }
     return epmValueCache.GetComplexValueProperties(complexValue, writingContent);
 }
示例#3
0
 internal static IEnumerable <ODataProperty> GetComplexValueProperties(EpmValueCache epmValueCache, ODataComplexValue complexValue, bool writingContent)
 {
     if (epmValueCache == null)
     {
         return(complexValue.Properties);
     }
     return(epmValueCache.GetComplexValueProperties(complexValue, writingContent));
 }
示例#4
0
        /// <summary>
        /// Writes a property with a complex value in ATOM format.
        /// </summary>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="propertyName">The name of the property being written.</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="beforeValueAction">Action called before the complex value is written, if it's actually 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="propertyTypeReference">The type information for the property being written.</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param>
        /// <param name="epmSourcePathSegment">The EPM source path segment which points to the property we're writing. (can be null)</param>
        /// <param name="complexValueProjectedProperties">Set of projected properties, or null if all properties should be written.</param>
        /// <returns>true if anything was written, false otherwise.</returns>
        private bool WriteComplexValueProperty(
            ODataComplexValue complexValue,
            string propertyName,
            bool isTopLevel,
            bool isWritingCollection,
            Action beforeValueAction,
            EpmValueCache epmValueCache,
            IEdmTypeReference propertyTypeReference,
            bool isOpenPropertyType,
            EpmSourcePathSegment epmSourcePathSegment,
            ProjectedPropertiesAnnotation complexValueProjectedProperties)
        {
            // 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(beforeValueAction, propertyName, isWritingCollection, /*isTopLevel*/ true);
                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(beforeValueAction, propertyName, isWritingCollection, /*isTopLevel*/ false),
                       this.WritePropertyEnd,
                       complexValuePropertyNamesChecker,
                       null /* collectionValidator */,
                       epmValueCache,
                       epmSourcePathSegment,
                       complexValueProjectedProperties));
        }
示例#5
0
 private static void CacheEpmSourcePathSegments(EpmValueCache valueCache, List <EpmSourcePathSegment> segments, IEnumerable <ODataProperty> properties)
 {
     if (properties != null)
     {
         foreach (EpmSourcePathSegment segment in segments)
         {
             ODataComplexValue value2;
             if ((segment.EpmInfo == null) && TryGetPropertyValue <ODataComplexValue>(properties, segment.PropertyName, out value2))
             {
                 IEnumerable <ODataProperty> enumerable = valueCache.CacheComplexValueProperties(value2);
                 CacheEpmSourcePathSegments(valueCache, segment.SubProperties, enumerable);
             }
         }
     }
 }
示例#6
0
        /// <summary>
        /// Returns the properties for the specified complex value.
        /// </summary>
        /// <param name="epmValueCache">The EPM value cache to use (can be null).</param>
        /// <param name="complexValue">The complex value to get the properties for.</param>
        /// <param name="writingContent">If we're writing content of an entry or not.</param>
        /// <returns>The properties enumeration for the complex value.</returns>
        internal static IEnumerable<ODataProperty> GetComplexValueProperties(
            EpmValueCache epmValueCache,
            ODataComplexValue complexValue,
            bool writingContent)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");
            Debug.Assert(writingContent || epmValueCache != null, "If we're not writing content, then the EPM value cache must exist.");

            if (epmValueCache == null)
            {
                return complexValue.Properties;
            }
            else
            {
                return epmValueCache.GetComplexValueProperties(complexValue, writingContent);
            }
        }
示例#7
0
        /// <summary>
        /// Returns the properties for the specified complex value.
        /// </summary>
        /// <param name="epmValueCache">The EPM value cache to use (can be null).</param>
        /// <param name="complexValue">The complex value to get the properties for.</param>
        /// <param name="writingContent">If we're writing content of an entry or not.</param>
        /// <returns>The properties enumeration for the complex value.</returns>
        internal static IEnumerable <ODataProperty> GetComplexValueProperties(
            EpmValueCache epmValueCache,
            ODataComplexValue complexValue,
            bool writingContent)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");
            Debug.Assert(writingContent || epmValueCache != null, "If we're not writing content, then the EPM value cache must exist.");

            if (epmValueCache == null)
            {
                return(complexValue.Properties);
            }
            else
            {
                return(epmValueCache.GetComplexValueProperties(complexValue, writingContent));
            }
        }
示例#8
0
        /// <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 top level 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,
                    /*isTopLevel*/ false,
                    isWritingCollection,
                    propertyWritten ? null : beforePropertiesAction,
                    epmValueCache,
                    epmSourcePathSegment,
                    duplicatePropertyNamesChecker,
                    projectedProperties);
            }

            if (afterPropertiesAction != null && propertyWritten)
            {
                afterPropertiesAction();
            }

            return(propertyWritten);
        }
示例#9
0
        /// <summary>
        /// Reads a property value starting on a complex value.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="complexValue">The complex value to start with.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="complexType">The type of the complex value.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadComplexPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            ODataComplexValue complexValue,
            EpmValueCache epmValueCache,
            int sourceSegmentIndex,
            IEdmComplexTypeReference complexType)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(sourceSegmentIndex >= 0, "sourceSegmentIndex >= 0");
            Debug.Assert(complexType != null, "complexType != null");
            Debug.Assert(complexValue != null, "complexValue != null");

            return(this.ReadPropertyValue(
                       epmInfo,
                       EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false),
                       sourceSegmentIndex,
                       complexType,
                       epmValueCache));
        }
        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;
        }
        /// <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;
        }
示例#12
0
        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);
        }
示例#13
0
        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);
        }
示例#14
0
        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);
        }
 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;
 }
示例#16
0
        /// <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);
        }
示例#17
0
        private object ReadPropertyValue(EntityPropertyMappingInfo epmInfo, IEnumerable <ODataProperty> cachedProperties, int sourceSegmentIndex, IEdmStructuredTypeReference structuredTypeReference, EpmValueCache epmValueCache)
        {
            EpmSourcePathSegment segment            = epmInfo.PropertyValuePath[sourceSegmentIndex];
            string             propertyName         = segment.PropertyName;
            bool               flag                 = epmInfo.PropertyValuePath.Length == (sourceSegmentIndex + 1);
            IEdmStructuredType owningStructuredType = structuredTypeReference.StructuredDefinition();
            IEdmProperty       expectedProperty     = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningStructuredType);

            if (expectedProperty != null)
            {
                if (flag)
                {
                    if (!expectedProperty.Type.IsODataPrimitiveTypeKind() && !expectedProperty.Type.IsNonEntityODataCollectionTypeKind())
                    {
                        throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                }
                else if (expectedProperty.Type.TypeKind() != EdmTypeKind.Complex)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                }
            }
            ODataProperty property2 = (cachedProperties == null) ? null : cachedProperties.FirstOrDefault <ODataProperty>(p => (p.Name == propertyName));

            if (property2 == null)
            {
                throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnInstance(propertyName, structuredTypeReference.ODataFullName()));
            }
            object            obj2         = property2.Value;
            ODataComplexValue complexValue = obj2 as ODataComplexValue;

            if (flag)
            {
                if (obj2 == null)
                {
                    WriterValidationUtils.ValidateNullPropertyValue(expectedProperty, this.WriterBehavior, this.atomOutputContext.Model);
                    return(obj2);
                }
                if (complexValue != null)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                }
                ODataCollectionValue value3 = obj2 as ODataCollectionValue;
                if (value3 != null)
                {
                    string str = value3.TypeName;
                    WriterValidationUtils.ResolveTypeNameForWriting(this.atomOutputContext.Model, (expectedProperty == null) ? null : expectedProperty.Type, ref str, EdmTypeKind.Collection, expectedProperty == null);
                    return(obj2);
                }
                if (obj2 is ODataStreamReferenceValue)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                }
                if (obj2 is ISpatial)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenPropertySpatialTypeCannotBeMapped(propertyName, epmInfo.DefiningType.FullName()));
                }
                if (expectedProperty != null)
                {
                    ValidationUtils.ValidateIsExpectedPrimitiveType(obj2, expectedProperty.Type);
                }
                return(obj2);
            }
            if (complexValue == null)
            {
                if (obj2 != null)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                }
                return(null);
            }
            string typeName = complexValue.TypeName;
            IEdmComplexTypeReference complexType = WriterValidationUtils.ResolveTypeNameForWriting(this.atomOutputContext.Model, (expectedProperty == null) ? null : expectedProperty.Type, ref typeName, EdmTypeKind.Complex, expectedProperty == null).AsComplexOrNull();

            return(this.ReadComplexPropertyValue(epmInfo, complexValue, epmValueCache, sourceSegmentIndex + 1, complexType));
        }
示例#18
0
 private object ReadComplexPropertyValue(EntityPropertyMappingInfo epmInfo, ODataComplexValue complexValue, EpmValueCache epmValueCache, int sourceSegmentIndex, IEdmComplexTypeReference complexType)
 {
     return this.ReadPropertyValue(epmInfo, EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false), sourceSegmentIndex, complexType, epmValueCache);
 }
示例#19
0
        /// <summary>
        /// Reads a property value starting on a complex value.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="complexValue">The complex value to start with.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="complexType">The type of the complex value.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadComplexPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            ODataComplexValue complexValue,
            EpmValueCache epmValueCache,
            int sourceSegmentIndex,
            IEdmComplexTypeReference complexType)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(sourceSegmentIndex >= 0, "sourceSegmentIndex >= 0");
            Debug.Assert(complexType != null, "complexType != null");
            Debug.Assert(complexValue != null, "complexValue != null");

            return this.ReadPropertyValue(
                epmInfo,
                EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false),
                sourceSegmentIndex,
                complexType,
                epmValueCache);
        }
示例#20
0
        /// <summary>
        /// Reads a property value starting with the specified index to the property value path.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="cachedProperties">The enumeration of properties to search for the first property in the property value path.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="structuredTypeReference">The type of the entry or complex value the <paramref name="cachedProperties"/> enumeration belongs to.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            IEnumerable<ODataProperty> cachedProperties,
            int sourceSegmentIndex,
            IEdmStructuredTypeReference structuredTypeReference,
            EpmValueCache epmValueCache)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(structuredTypeReference != null, "structuredTypeReference != null");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");

            EpmSourcePathSegment sourceSegment = epmInfo.PropertyValuePath[sourceSegmentIndex];
            string propertyName = sourceSegment.PropertyName;
            bool lastSegment = epmInfo.PropertyValuePath.Length == sourceSegmentIndex + 1;

            IEdmStructuredType structuredType = structuredTypeReference.StructuredDefinition();
            IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, structuredType);
            if (edmProperty != null)
            {
                // If this is the last part of the path, then it has to be a primitive or atomic collection type otherwise should be a complex type
                if (lastSegment)
                {
                    if (!edmProperty.Type.IsODataPrimitiveTypeKind() && !edmProperty.Type.IsNonEntityODataCollectionTypeKind())
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                }
                else
                {
                    if (edmProperty.Type.TypeKind() != EdmTypeKind.Complex)
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                    }
                }
            }
            else
            {
                Debug.Assert(
                    structuredType.IsOpen,
                    "Only open types can have undeclared properties, otherwise we should have failed in the ValidatePropertyDefined method.");
            }

            ODataProperty property = cachedProperties == null ? null : cachedProperties.FirstOrDefault(p => p.Name == propertyName);
            if (property == null)
            {
                throw new ODataException(o.Strings.EpmSourceTree_MissingPropertyOnInstance(propertyName, structuredTypeReference.ODataFullName()));
            }

            object propertyValue = property.Value;
            ODataComplexValue propertyComplexValue = propertyValue as ODataComplexValue;
            if (lastSegment)
            {
                if (propertyValue == null)
                {
                    WriterValidationUtils.ValidateNullPropertyValue(edmProperty, this.WriterBehavior, this.atomOutputContext.Model);
                }
                else
                {
                    // If this property is the last one it has to be either a primitive or collection
                    if (propertyComplexValue != null)
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                    else
                    {
                        ODataCollectionValue propertyCollectionValue = propertyValue as ODataCollectionValue;
                        if (propertyCollectionValue != null)
                        {
                            // Validate the type name for the collection
                            string typeName = propertyCollectionValue.TypeName;
                            WriterValidationUtils.ResolveTypeNameForWriting(
                                this.atomOutputContext.Model,
                                edmProperty == null ? null : edmProperty.Type,
                                ref typeName,
                                EdmTypeKind.Collection,
                                edmProperty == null);
                        }
                        else
                        {
                            if (propertyValue is ODataStreamReferenceValue)
                            {
                                // Stream properties should not come here, if it were an ODataEntry property it would have been 
                                // filtered in ReadEntryPropertyValue() by "epmValueCache.EntryProperties" call.
                                throw new ODataException(o.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                            }
                            else if (propertyValue is ISpatial)
                            {
                                throw new ODataException(o.Strings.EpmSourceTree_OpenPropertySpatialTypeCannotBeMapped(propertyName, epmInfo.DefiningType.FullName()));
                            }
                            else if (edmProperty != null)
                            {
                                ValidationUtils.ValidateIsExpectedPrimitiveType(propertyValue, edmProperty.Type);
                            }
                        }
                    }
                }

                return propertyValue;
            }

            // Otherwise it's in the middle and thus it must be a complex value
            if (propertyComplexValue == null)
            {
                if (propertyValue != null)
                {
                    // It's not a complex value - fail.
                    throw new ODataException(o.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                }
                else
                {
                    // The value of the property is null, which can be a null complex value
                    // Note that we must not attempt to resolve the type as if the type name was null here, because
                    //  1) We don't need the type for anything anyway (the value is null, this is the end)
                    //  2) If the property is open, trying to resolve a null type name would throw
                    //     but we don't have a null type name, we have a null entire value.
                    return null;
                }
            }

            string localTypeName = propertyComplexValue.TypeName;
            IEdmComplexTypeReference complexValueType = WriterValidationUtils.ResolveTypeNameForWriting(
                this.atomOutputContext.Model,
                edmProperty == null ? null : edmProperty.Type,
                ref localTypeName,
                EdmTypeKind.Complex,
                edmProperty == null).AsComplexOrNull();

            return this.ReadComplexPropertyValue(
                epmInfo,
                propertyComplexValue,
                epmValueCache,
                sourceSegmentIndex + 1,
                complexValueType);
        }
 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;
 }
示例#22
0
        /// <summary>
        /// Reads a property value starting with the specified index to the property value path.
        /// </summary>
        /// <param name="epmInfo">The EPM info which describes the mapping for which to read the property value.</param>
        /// <param name="cachedProperties">The enumeration of properties to search for the first property in the property value path.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="structuredTypeReference">The type of the entry or complex value the <paramref name="cachedProperties"/> enumeration belongs to.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadPropertyValue(
            EntityPropertyMappingInfo epmInfo,
            IEnumerable <ODataProperty> cachedProperties,
            int sourceSegmentIndex,
            IEdmStructuredTypeReference structuredTypeReference,
            EpmValueCache epmValueCache)
        {
            Debug.Assert(epmInfo != null, "epmInfo != null");
            Debug.Assert(epmInfo.PropertyValuePath != null, "The PropertyValuePath should have been initialized by now.");
            Debug.Assert(epmInfo.PropertyValuePath.Length > sourceSegmentIndex, "The PropertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(structuredTypeReference != null, "structuredTypeReference != null");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");

            EpmSourcePathSegment sourceSegment = epmInfo.PropertyValuePath[sourceSegmentIndex];
            string propertyName = sourceSegment.PropertyName;
            bool   lastSegment  = epmInfo.PropertyValuePath.Length == sourceSegmentIndex + 1;

            IEdmStructuredType structuredType = structuredTypeReference.StructuredDefinition();
            IEdmProperty       edmProperty    = WriterValidationUtils.ValidatePropertyDefined(propertyName, structuredType);

            if (edmProperty != null)
            {
                // If this is the last part of the path, then it has to be a primitive or atomic collection type otherwise should be a complex type
                if (lastSegment)
                {
                    if (!edmProperty.Type.IsODataPrimitiveTypeKind() && !edmProperty.Type.IsNonEntityODataCollectionTypeKind())
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                }
                else
                {
                    if (edmProperty.Type.TypeKind() != EdmTypeKind.Complex)
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                    }
                }
            }
            else
            {
                Debug.Assert(
                    structuredType.IsOpen,
                    "Only open types can have undeclared properties, otherwise we should have failed in the ValidatePropertyDefined method.");
            }

            ODataProperty property = cachedProperties == null ? null : cachedProperties.FirstOrDefault(p => p.Name == propertyName);

            if (property == null)
            {
                throw new ODataException(o.Strings.EpmSourceTree_MissingPropertyOnInstance(propertyName, structuredTypeReference.ODataFullName()));
            }

            object            propertyValue        = property.Value;
            ODataComplexValue propertyComplexValue = propertyValue as ODataComplexValue;

            if (lastSegment)
            {
                if (propertyValue == null)
                {
                    WriterValidationUtils.ValidateNullPropertyValue(edmProperty, this.WriterBehavior, this.atomOutputContext.Model);
                }
                else
                {
                    // If this property is the last one it has to be either a primitive or collection
                    if (propertyComplexValue != null)
                    {
                        throw new ODataException(o.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
                    }
                    else
                    {
                        ODataCollectionValue propertyCollectionValue = propertyValue as ODataCollectionValue;
                        if (propertyCollectionValue != null)
                        {
                            // Validate the type name for the collection
                            string typeName = propertyCollectionValue.TypeName;
                            WriterValidationUtils.ResolveTypeNameForWriting(
                                this.atomOutputContext.Model,
                                edmProperty == null ? null : edmProperty.Type,
                                ref typeName,
                                EdmTypeKind.Collection,
                                edmProperty == null);
                        }
                        else
                        {
                            if (propertyValue is ODataStreamReferenceValue)
                            {
                                // Stream properties should not come here, if it were an ODataEntry property it would have been
                                // filtered in ReadEntryPropertyValue() by "epmValueCache.EntryProperties" call.
                                throw new ODataException(o.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
                            }
                            else if (propertyValue is ISpatial)
                            {
                                throw new ODataException(o.Strings.EpmSourceTree_OpenPropertySpatialTypeCannotBeMapped(propertyName, epmInfo.DefiningType.FullName()));
                            }
                            else if (edmProperty != null)
                            {
                                ValidationUtils.ValidateIsExpectedPrimitiveType(propertyValue, edmProperty.Type);
                            }
                        }
                    }
                }

                return(propertyValue);
            }

            // Otherwise it's in the middle and thus it must be a complex value
            if (propertyComplexValue == null)
            {
                if (propertyValue != null)
                {
                    // It's not a complex value - fail.
                    throw new ODataException(o.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
                }
                else
                {
                    // The value of the property is null, which can be a null complex value
                    // Note that we must not attempt to resolve the type as if the type name was null here, because
                    //  1) We don't need the type for anything anyway (the value is null, this is the end)
                    //  2) If the property is open, trying to resolve a null type name would throw
                    //     but we don't have a null type name, we have a null entire value.
                    return(null);
                }
            }

            string localTypeName = propertyComplexValue.TypeName;
            IEdmComplexTypeReference complexValueType = WriterValidationUtils.ResolveTypeNameForWriting(
                this.atomOutputContext.Model,
                edmProperty == null ? null : edmProperty.Type,
                ref localTypeName,
                EdmTypeKind.Complex,
                edmProperty == null).AsComplexOrNull();

            return(this.ReadComplexPropertyValue(
                       epmInfo,
                       propertyComplexValue,
                       epmValueCache,
                       sourceSegmentIndex + 1,
                       complexValueType));
        }
示例#23
0
        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);
        }
        /// <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;
        }
示例#25
0
        /// <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);
        }
 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;
 }
示例#27
0
 private object ReadPropertyValue(EntityPropertyMappingInfo epmInfo, IEnumerable<ODataProperty> cachedProperties, int sourceSegmentIndex, IEdmStructuredTypeReference structuredTypeReference, EpmValueCache epmValueCache)
 {
     EpmSourcePathSegment segment = epmInfo.PropertyValuePath[sourceSegmentIndex];
     string propertyName = segment.PropertyName;
     bool flag = epmInfo.PropertyValuePath.Length == (sourceSegmentIndex + 1);
     IEdmStructuredType owningStructuredType = structuredTypeReference.StructuredDefinition();
     IEdmProperty expectedProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningStructuredType);
     if (expectedProperty != null)
     {
         if (flag)
         {
             if (!expectedProperty.Type.IsODataPrimitiveTypeKind() && !expectedProperty.Type.IsNonEntityODataCollectionTypeKind())
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
             }
         }
         else if (expectedProperty.Type.TypeKind() != EdmTypeKind.Complex)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
         }
     }
     ODataProperty property2 = (cachedProperties == null) ? null : cachedProperties.FirstOrDefault<ODataProperty>(p => (p.Name == propertyName));
     if (property2 == null)
     {
         throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnInstance(propertyName, structuredTypeReference.ODataFullName()));
     }
     object obj2 = property2.Value;
     ODataComplexValue complexValue = obj2 as ODataComplexValue;
     if (flag)
     {
         if (obj2 == null)
         {
             WriterValidationUtils.ValidateNullPropertyValue(expectedProperty, this.WriterBehavior, this.atomOutputContext.Model);
             return obj2;
         }
         if (complexValue != null)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(propertyName));
         }
         ODataCollectionValue value3 = obj2 as ODataCollectionValue;
         if (value3 != null)
         {
             string str = value3.TypeName;
             WriterValidationUtils.ResolveTypeNameForWriting(this.atomOutputContext.Model, (expectedProperty == null) ? null : expectedProperty.Type, ref str, EdmTypeKind.Collection, expectedProperty == null);
             return obj2;
         }
         if (obj2 is ODataStreamReferenceValue)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName));
         }
         if (obj2 is ISpatial)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenPropertySpatialTypeCannotBeMapped(propertyName, epmInfo.DefiningType.FullName()));
         }
         if (expectedProperty != null)
         {
             ValidationUtils.ValidateIsExpectedPrimitiveType(obj2, expectedProperty.Type);
         }
         return obj2;
     }
     if (complexValue == null)
     {
         if (obj2 != null)
         {
             throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_TraversalOfNonComplexType(propertyName));
         }
         return null;
     }
     string typeName = complexValue.TypeName;
     IEdmComplexTypeReference complexType = WriterValidationUtils.ResolveTypeNameForWriting(this.atomOutputContext.Model, (expectedProperty == null) ? null : expectedProperty.Type, ref typeName, EdmTypeKind.Complex, expectedProperty == null).AsComplexOrNull();
     return this.ReadComplexPropertyValue(epmInfo, complexValue, epmValueCache, sourceSegmentIndex + 1, complexType);
 }
示例#28
0
 private object ReadComplexPropertyValue(EntityPropertyMappingInfo epmInfo, ODataComplexValue complexValue, EpmValueCache epmValueCache, int sourceSegmentIndex, IEdmComplexTypeReference complexType)
 {
     return(this.ReadPropertyValue(epmInfo, EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, false), sourceSegmentIndex, complexType, epmValueCache));
 }