コード例 #1
0
ファイル: WriterValidator.cs プロジェクト: ificator/odata.net
        /// <inheritdoc/>
        public IDuplicatePropertyNameChecker GetDuplicatePropertyNameChecker()
        {
            IDuplicatePropertyNameChecker duplicatePropertyNameChecker;

            if (settings.ThrowOnDuplicatePropertyNames)
            {
#if NETSTANDARD2_0_OR_GREATER
                if (this.duplicatePropertyNameCheckerObjectPool == null)
                {
                    DefaultObjectPoolProvider poolProvider = new DefaultObjectPoolProvider {
                        MaximumRetained = 8
                    };
                    this.duplicatePropertyNameCheckerObjectPool = poolProvider.Create <DuplicatePropertyNameChecker>();
                }

                duplicatePropertyNameChecker = this.duplicatePropertyNameCheckerObjectPool.Get();
                duplicatePropertyNameChecker.Reset();
#else
                duplicatePropertyNameChecker = new DuplicatePropertyNameChecker();
#endif
            }
            else
            {
                if (this.nullDuplicatePropertyNameChecker == null)
                {
                    // NullDuplicatePropertyNameChecker does nothing, so we can use a single instance during the writing process.
                    this.nullDuplicatePropertyNameChecker = new NullDuplicatePropertyNameChecker();
                }

                duplicatePropertyNameChecker = this.nullDuplicatePropertyNameChecker;
            }

            return(duplicatePropertyNameChecker);
        }
コード例 #2
0
ファイル: WriterValidator.cs プロジェクト: ificator/odata.net
        /// <inheritdoc/>
        public void ReturnDuplicatePropertyNameChecker(IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
        {
#if NETSTANDARD2_0_OR_GREATER
            // We only return the DuplicatePropertyNameChecker to the object pool and ignore the NullDuplicatePropertyNameChecker.
            if (duplicatePropertyNameChecker is DuplicatePropertyNameChecker duplicateChecker)
            {
                this.duplicatePropertyNameCheckerObjectPool.Return(duplicateChecker);
            }
#endif
        }
コード例 #3
0
        /// <summary>
        /// Asynchronously writes out the value of a resource (complex or entity).
        /// </summary>
        /// <param name="resourceValue">The resource (complex or entity) value to write.</param>
        /// <param name="metadataTypeReference">The metadata type for the resource value.</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open (dynamic) property.</param>
        /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param>
        /// <remarks>The current recursion depth should be a value, measured by the number of resource and collection values between
        /// this resource value and the top-level payload, not including this one.</remarks>
        /// <returns>A task that represents the asynchronous write operation.</returns>
        public virtual async Task WriteResourceValueAsync(
            ODataResourceValue resourceValue,
            IEdmTypeReference metadataTypeReference,
            bool isOpenPropertyType,
            IDuplicatePropertyNameChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(resourceValue != null, "resourceValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire resource instance;
            await this.AsynchronousJsonWriter.StartObjectScopeAsync().ConfigureAwait(false);

            string typeName = resourceValue.TypeName;

            // In requests, we allow the property type reference to be null if the type name is specified in the OM
            if (metadataTypeReference == null && !this.WritingResponse && typeName == null && this.Model.IsUserModel())
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueSerializer_NoExpectedTypeOrTypeNameSpecifiedForResourceValueRequest);
            }

            // Resolve the type name to the type; if no type name is specified we will use the type inferred from metadata.
            IEdmStructuredTypeReference resourceValueTypeReference =
                (IEdmStructuredTypeReference)TypeNameOracle.ResolveAndValidateTypeForResourceValue(this.Model, metadataTypeReference, resourceValue, isOpenPropertyType, this.WriterValidator);

            Debug.Assert(
                metadataTypeReference == null || resourceValueTypeReference == null || EdmLibraryExtensions.IsAssignableFrom(metadataTypeReference, resourceValueTypeReference),
                "Complex property types must be the same as or inherit from the ones from metadata (unless open).");

            typeName = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(resourceValue, metadataTypeReference, resourceValueTypeReference, isOpenPropertyType);
            if (typeName != null)
            {
                await this.AsynchronousODataAnnotationWriter.WriteODataTypeInstanceAnnotationAsync(typeName)
                .ConfigureAwait(false);
            }

            // Write custom instance annotations
            await this.InstanceAnnotationWriter.WriteInstanceAnnotationsAsync(resourceValue.InstanceAnnotations)
            .ConfigureAwait(false);

            // Write the properties of the resource value as usual. Note we do not allow resource types to contain named stream properties.
            await this.PropertySerializer.WritePropertiesAsync(
                resourceValueTypeReference == null?null : resourceValueTypeReference.StructuredDefinition(),
                resourceValue.Properties,
                true /* isComplexValue */,
                duplicatePropertyNamesChecker,
                null).ConfigureAwait(false);

            // End the object scope which represents the resource instance;
            await this.AsynchronousJsonWriter.EndObjectScopeAsync().ConfigureAwait(false);

            this.DecreaseRecursionDepth();
        }
コード例 #4
0
        /// <summary>
        /// Writes the property information for a property.
        /// </summary>
        /// <param name="propertyInfo">The property info to write out.</param>
        /// <param name="owningType">The owning type for the <paramref name="propertyInfo"/> or null if no metadata is available.</param>
        /// <param name="isTopLevel">true when writing a top-level property; false for nested properties.</param>
        /// <param name="duplicatePropertyNameChecker">The DuplicatePropertyNameChecker to use.</param>
        /// <param name="metadataBuilder">The metadatabuilder for the resource</param>
        internal void WritePropertyInfo(
            ODataPropertyInfo propertyInfo,
            IEdmStructuredType owningType,
            bool isTopLevel,
            IDuplicatePropertyNameChecker duplicatePropertyNameChecker,
            ODataResourceMetadataBuilder metadataBuilder)
        {
            WriterValidationUtils.ValidatePropertyNotNull(propertyInfo);

            string propertyName = propertyInfo.Name;

            if (this.JsonLightOutputContext.MessageWriterSettings.Validations != ValidationKinds.None)
            {
                WriterValidationUtils.ValidatePropertyName(propertyName);
            }

            if (!this.JsonLightOutputContext.PropertyCacheHandler.InResourceSetScope())
            {
                this.currentPropertyInfo = new PropertySerializationInfo(this.JsonLightOutputContext.Model, propertyName, owningType)
                {
                    IsTopLevel = isTopLevel
                };
            }
            else
            {
                this.currentPropertyInfo = this.JsonLightOutputContext.PropertyCacheHandler.GetProperty(this.JsonLightOutputContext.Model, propertyName, owningType);
            }

            WriterValidationUtils.ValidatePropertyDefined(this.currentPropertyInfo, this.MessageWriterSettings.ThrowOnUndeclaredPropertyForNonOpenType);

            duplicatePropertyNameChecker.ValidatePropertyUniqueness(propertyInfo);

            if (currentPropertyInfo.MetadataType.IsUndeclaredProperty)
            {
                WriteODataTypeAnnotation(propertyInfo, isTopLevel);
            }

            WriteInstanceAnnotation(propertyInfo, isTopLevel, currentPropertyInfo.MetadataType.IsUndeclaredProperty);

            ODataStreamPropertyInfo streamInfo = propertyInfo as ODataStreamPropertyInfo;

            if (streamInfo != null && !(this.JsonLightOutputContext.MetadataLevel is JsonNoMetadataLevel))
            {
                Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level.");
                WriteStreamValue(streamInfo, propertyInfo.Name, metadataBuilder);
            }
        }
コード例 #5
0
        /// <summary>
        /// Writes property names and value pairs.
        /// </summary>
        /// <param name="owningType">The <see cref="IEdmStructuredType"/> of the resource (or null if not metadata is available).</param>
        /// <param name="properties">The enumeration of properties to write out.</param>
        /// <param name="isComplexValue">
        /// Whether the properties are being written for complex value. Also used for detecting whether stream properties
        /// are allowed as named stream properties should only be defined on ODataResource instances
        /// </param>
        /// <param name="duplicatePropertyNameChecker">The DuplicatePropertyNameChecker to use.</param>
        internal void WriteProperties(
            IEdmStructuredType owningType,
            IEnumerable <ODataProperty> properties,
            bool isComplexValue,
            IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
        {
            if (properties == null)
            {
                return;
            }

            foreach (ODataProperty property in properties)
            {
                this.WriteProperty(
                    property,
                    owningType,
                    false /* isTopLevel */,
                    !isComplexValue,
                    duplicatePropertyNameChecker);
            }
        }
コード例 #6
0
        /// <summary>
        /// Write a literal value in JSON Light format.
        /// </summary>
        /// <param name="model">EDM Model to use for validation and type lookups.</param>
        /// <param name="messageWriterSettings">Settings to use when writing.</param>
        /// <param name="textWriter">TextWriter to use as the output for the value.</param>
        /// <param name="writeValue">Delegate to use to actually write the value.</param>
        /// <param name="isResourceValue">We want to pass the <see cref="IDuplicatePropertyNameChecker"/> instance to the Action delegate when writing Resource value but not Collection value.</param>
        private static void WriteJsonLightLiteral(IEdmModel model, ODataMessageWriterSettings messageWriterSettings, TextWriter textWriter, Action <ODataJsonLightValueSerializer, IDuplicatePropertyNameChecker> writeValue, bool isResourceValue = true)
        {
            IEnumerable <KeyValuePair <string, string> > parameters = new Dictionary <string, string>
            {
                { MimeConstants.MimeIeee754CompatibleParameterName, messageWriterSettings.IsIeee754Compatible.ToString() }
            };
            ODataMediaType mediaType = new ODataMediaType(MimeConstants.MimeApplicationType, MimeConstants.MimeJsonSubType, parameters);

            // Calling dispose since it's the right thing to do, but when created from a custom-built TextWriter
            // the output context Dispose will not actually dispose anything, it will just cleanup itself.
            // TODO: URI parser will also support DI container in the future but set the container to null at this moment.
            ODataMessageInfo messageInfo = new ODataMessageInfo
            {
                Model      = model,
                IsAsync    = false,
                IsResponse = false,
                MediaType  = mediaType
            };

            using (ODataJsonLightOutputContext jsonOutputContext =
                       new ODataJsonLightOutputContext(textWriter, messageInfo, messageWriterSettings))
            {
                ODataJsonLightValueSerializer jsonLightValueSerializer = new ODataJsonLightValueSerializer(jsonOutputContext);

                if (!isResourceValue)
                {
                    writeValue(jsonLightValueSerializer, null);
                }
                else
                {
                    IDuplicatePropertyNameChecker duplicatePropertyNameChecker = jsonLightValueSerializer.GetDuplicatePropertyNameChecker();
                    writeValue(jsonLightValueSerializer, duplicatePropertyNameChecker);
                    jsonLightValueSerializer.ReturnDuplicatePropertyNameChecker(duplicatePropertyNameChecker);
                }

                jsonLightValueSerializer.AssertRecursionDepthIsZero();
            }
        }
コード例 #7
0
        internal void WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool isTopLevel,
            IDuplicatePropertyNameChecker duplicatePropertyNameChecker,
            ODataResourceMetadataBuilder metadataBuilder)
        {
            this.WritePropertyInfo(property, owningType, isTopLevel, duplicatePropertyNameChecker, metadataBuilder);

            ODataValue value = property.ODataValue;

            // handle ODataUntypedValue
            ODataUntypedValue untypedValue = value as ODataUntypedValue;

            if (untypedValue != null)
            {
                WriteUntypedValue(untypedValue);
                return;
            }

            ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;

            if (streamReferenceValue != null && !(this.JsonLightOutputContext.MetadataLevel is JsonNoMetadataLevel))
            {
                Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level.");
                WriteStreamValue(streamReferenceValue, property.Name, metadataBuilder);
                return;
            }

            if (value is ODataNullValue || value == null)
            {
                this.WriteNullProperty(property);
                return;
            }

            bool isOpenPropertyType = this.IsOpenProperty(property);

            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                this.WritePrimitiveProperty(primitiveValue, isOpenPropertyType);
                return;
            }

            ODataEnumValue enumValue = value as ODataEnumValue;

            if (enumValue != null)
            {
                this.WriteEnumProperty(enumValue, isOpenPropertyType);
                return;
            }

            ODataResourceValue resourceValue = value as ODataResourceValue;

            if (resourceValue != null)
            {
                if (isTopLevel)
                {
                    throw new ODataException(Strings.ODataMessageWriter_NotAllowedWriteTopLevelPropertyWithResourceValue(property.Name));
                }

                this.WriteResourceProperty(property, resourceValue, isOpenPropertyType);
                return;
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                if (isTopLevel)
                {
                    if (collectionValue.Items != null && collectionValue.Items.Any(i => i is ODataResourceValue))
                    {
                        throw new ODataException(Strings.ODataMessageWriter_NotAllowedWriteTopLevelPropertyWithResourceValue(property.Name));
                    }
                }

                this.WriteCollectionProperty(collectionValue, isOpenPropertyType);
                return;
            }

            ODataBinaryStreamValue streamValue = value as ODataBinaryStreamValue;

            if (streamValue != null)
            {
                this.WriteStreamProperty(streamValue, isOpenPropertyType);
                return;
            }
        }
コード例 #8
0
        /// <summary>
        /// Asynchronously writes an instance annotation.
        /// </summary>
        /// <param name="instanceAnnotation">The instance annotation to write.</param>
        /// <param name="ignoreFilter">Whether to ignore the filter in settings.</param>
        /// <param name="propertyName">The name of the property this instance annotation applies tos</param>
        internal async Task WriteInstanceAnnotationAsync(
            ODataInstanceAnnotation instanceAnnotation,
            bool ignoreFilter   = false,
            string propertyName = null)
        {
            string     annotationName  = instanceAnnotation.Name;
            ODataValue annotationValue = instanceAnnotation.Value;

            Debug.Assert(!string.IsNullOrEmpty(annotationName), "annotationName should not be null or empty");
            Debug.Assert(annotationValue != null, "annotationValue should not be null because we use ODataNullValue for null instead");
            Debug.Assert(!(annotationValue is ODataStreamReferenceValue), "!(annotationValue is ODataStreamReferenceValue) -- ODataInstanceAnnotation and InstanceAnnotationCollection will throw if the value is a stream value.");
            Debug.Assert(this.valueSerializer.Model != null, "this.valueSerializer.Model != null");

            if (!ignoreFilter && this.valueSerializer.MessageWriterSettings.ShouldSkipAnnotation(annotationName))
            {
                return;
            }

            IEdmTypeReference expectedType = MetadataUtils.LookupTypeOfTerm(annotationName, this.valueSerializer.Model);

            if (annotationValue is ODataNullValue)
            {
                if (expectedType != null && !expectedType.IsNullable)
                {
                    throw new ODataException(
                              ODataErrorStrings.JsonLightInstanceAnnotationWriter_NullValueNotAllowedForInstanceAnnotation(
                                  annotationName, expectedType.FullName()));
                }

                await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName)
                .ConfigureAwait(false);

                await this.valueSerializer.WriteNullValueAsync()
                .ConfigureAwait(false);

                return;
            }

            // If we didn't find an expected type from looking up the term in the model, treat this value the same way we would for open property values.
            // That is, write the type name (unless its a primitive value with a JSON-native type).  If we did find an expected type, treat the annotation value like a
            // declared property with an expected type. This will still write out the type if the value type is more derived than the declared type, for example.
            bool treatLikeOpenProperty = expectedType == null;

            ODataResourceValue resourceValue = annotationValue as ODataResourceValue;

            if (resourceValue != null)
            {
                IDuplicatePropertyNameChecker duplicatePropertyNameChecker = this.valueSerializer.GetDuplicatePropertyNameChecker();
                await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName)
                .ConfigureAwait(false);

                await this.valueSerializer.WriteResourceValueAsync(resourceValue,
                                                                   expectedType,
                                                                   treatLikeOpenProperty,
                                                                   duplicatePropertyNameChecker).ConfigureAwait(false);

                this.valueSerializer.ReturnDuplicatePropertyNameChecker(duplicatePropertyNameChecker);

                return;
            }

            ODataCollectionValue collectionValue = annotationValue as ODataCollectionValue;

            if (collectionValue != null)
            {
                IEdmTypeReference typeFromCollectionValue = (IEdmCollectionTypeReference)TypeNameOracle.ResolveAndValidateTypeForCollectionValue(
                    this.valueSerializer.Model, expectedType, collectionValue, treatLikeOpenProperty, this.writerValidator);
                string collectionTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(collectionValue, expectedType, typeFromCollectionValue, treatLikeOpenProperty);
                if (collectionTypeNameToWrite != null)
                {
                    await this.asynchronousODataAnnotationWriter.WriteODataTypePropertyAnnotationAsync(annotationName, collectionTypeNameToWrite)
                    .ConfigureAwait(false);
                }

                await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName)
                .ConfigureAwait(false);

                await this.valueSerializer.WriteCollectionValueAsync(
                    collectionValue,
                    expectedType,
                    typeFromCollectionValue,
                    false /*isTopLevelProperty*/,
                    false /*isInUri*/,
                    treatLikeOpenProperty).ConfigureAwait(false);

                return;
            }

            ODataUntypedValue untypedValue = annotationValue as ODataUntypedValue;

            if (untypedValue != null)
            {
                await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName)
                .ConfigureAwait(false);

                await this.valueSerializer.WriteUntypedValueAsync(untypedValue)
                .ConfigureAwait(false);

                return;
            }

            ODataEnumValue enumValue = annotationValue as ODataEnumValue;

            if (enumValue != null)
            {
                await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName)
                .ConfigureAwait(false);

                await this.valueSerializer.WriteEnumValueAsync(enumValue, expectedType)
                .ConfigureAwait(false);

                return;
            }

            ODataPrimitiveValue primitiveValue = annotationValue as ODataPrimitiveValue;

            Debug.Assert(primitiveValue != null, "Did we add a new subclass of ODataValue?");

            IEdmTypeReference typeFromPrimitiveValue = TypeNameOracle.ResolveAndValidateTypeForPrimitiveValue(primitiveValue);

            string primitiveTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(primitiveValue, expectedType, typeFromPrimitiveValue, treatLikeOpenProperty);

            if (primitiveTypeNameToWrite != null)
            {
                await this.asynchronousODataAnnotationWriter.WriteODataTypePropertyAnnotationAsync(annotationName, primitiveTypeNameToWrite)
                .ConfigureAwait(false);
            }

            await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName)
            .ConfigureAwait(false);

            await this.valueSerializer.WritePrimitiveValueAsync(primitiveValue.Value, typeFromPrimitiveValue, expectedType)
            .ConfigureAwait(false);
        }
コード例 #9
0
        /// <summary>
        /// Asynchronously writes out the value of a collection property.
        /// </summary>
        /// <param name="collectionValue">The collection value to write.</param>
        /// <param name="metadataTypeReference">The metadata type reference for the collection.</param>
        /// <param name="valueTypeReference">The value type reference for the collection.</param>
        /// <param name="isTopLevelProperty">Whether or not a top-level property is being written.</param>
        /// <param name="isInUri">Whether or not the value is being written for a URI.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <remarks>The current recursion depth is measured by the number of resource and collection values between
        /// this one and the top-level payload, not including this one.</remarks>
        /// <returns>A task that represents the asynchronous write operation.</returns>
        public virtual async Task WriteCollectionValueAsync(
            ODataCollectionValue collectionValue,
            IEdmTypeReference metadataTypeReference,
            IEdmTypeReference valueTypeReference,
            bool isTopLevelProperty,
            bool isInUri,
            bool isOpenPropertyType)
        {
            Debug.Assert(collectionValue != null, "collectionValue != null");
            Debug.Assert(!isTopLevelProperty || !isInUri, "Cannot be a top level property and in a uri");

            this.IncreaseRecursionDepth();

            // If the CollectionValue has type information write out the metadata and the type in it.
            string typeName = collectionValue.TypeName;

            if (isTopLevelProperty)
            {
                Debug.Assert(metadataTypeReference == null, "Never expect a metadata type for top-level properties.");
                if (typeName == null)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightValueSerializer_MissingTypeNameOnCollection);
                }
            }
            else
            {
                // In requests, we allow the metadata type reference to be null if the type name is specified in the OM
                if (metadataTypeReference == null && !this.WritingResponse && typeName == null && this.Model.IsUserModel())
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueSerializer_NoExpectedTypeOrTypeNameSpecifiedForCollectionValueInRequest);
                }
            }

            if (valueTypeReference == null)
            {
                valueTypeReference = TypeNameOracle.ResolveAndValidateTypeForCollectionValue(this.Model, metadataTypeReference, collectionValue, isOpenPropertyType, this.WriterValidator);
            }

            bool useValueProperty = false;

            if (isInUri)
            {
                // resolve the type name to the type; if no type name is specified we will use the
                // type inferred from metadata
                typeName = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, metadataTypeReference, valueTypeReference, isOpenPropertyType);
                if (!string.IsNullOrEmpty(typeName))
                {
                    useValueProperty = true;

                    // "{"
                    await this.AsynchronousJsonWriter.StartObjectScopeAsync().ConfigureAwait(false);

                    await this.AsynchronousODataAnnotationWriter.WriteODataTypeInstanceAnnotationAsync(typeName)
                    .ConfigureAwait(false);

                    await this.AsynchronousJsonWriter.WriteValuePropertyNameAsync().ConfigureAwait(false);
                }
            }

            // [
            // This represents the array of items in the CollectionValue
            await this.AsynchronousJsonWriter.StartArrayScopeAsync().ConfigureAwait(false);

            // Iterate through the CollectionValue items and write them out (treat null Items as an empty enumeration)
            IEnumerable items = collectionValue.Items;

            if (items != null)
            {
                IEdmTypeReference expectedItemTypeReference = valueTypeReference == null ? null : ((IEdmCollectionTypeReference)valueTypeReference).ElementType();

                IDuplicatePropertyNameChecker duplicatePropertyNamesChecker = null;
                foreach (object item in items)
                {
                    ValidationUtils.ValidateCollectionItem(item, expectedItemTypeReference.IsNullable());

                    ODataResourceValue itemAsResourceValue = item as ODataResourceValue;
                    if (itemAsResourceValue != null)
                    {
                        if (duplicatePropertyNamesChecker == null)
                        {
                            duplicatePropertyNamesChecker = this.GetDuplicatePropertyNameChecker();
                        }

                        await this.WriteResourceValueAsync(
                            itemAsResourceValue,
                            expectedItemTypeReference,
                            false /*isOpenPropertyType*/,
                            duplicatePropertyNamesChecker).ConfigureAwait(false);

                        duplicatePropertyNamesChecker.Reset();
                    }
                    else
                    {
                        Debug.Assert(!(item is ODataCollectionValue), "!(item is ODataCollectionValue)");
                        Debug.Assert(!(item is ODataStreamReferenceValue), "!(item is ODataStreamReferenceValue)");

                        // by design: collection element's type name is not written for enum or non-spatial primitive value even in case of full metadata.
                        // because enum and non-spatial primitive types don't have inheritance, the type of each element is the same as the item type of the collection, whose type name for spatial types in full metadata mode.
                        ODataEnumValue enumValue = item as ODataEnumValue;
                        if (enumValue != null)
                        {
                            await this.WriteEnumValueAsync(enumValue, expectedItemTypeReference).ConfigureAwait(false);
                        }
                        else
                        {
                            ODataUntypedValue untypedValue = item as ODataUntypedValue;
                            if (untypedValue != null)
                            {
                                await this.WriteUntypedValueAsync(untypedValue).ConfigureAwait(false);
                            }
                            else if (item != null)
                            {
                                await this.WritePrimitiveValueAsync(item, expectedItemTypeReference).ConfigureAwait(false);
                            }
                            else
                            {
                                await this.WriteNullValueAsync().ConfigureAwait(false);
                            }
                        }
                    }
                }

                if (duplicatePropertyNamesChecker != null)
                {
                    this.ReturnDuplicatePropertyNameChecker(duplicatePropertyNamesChecker);
                }
            }

            // End the array scope which holds the items
            await this.AsynchronousJsonWriter.EndArrayScopeAsync().ConfigureAwait(false);

            if (useValueProperty)
            {
                await this.AsynchronousJsonWriter.EndObjectScopeAsync().ConfigureAwait(false);
            }

            this.DecreaseRecursionDepth();
        }
コード例 #10
0
        private void WriteProperty(
            ODataProperty property,
            IEdmStructuredType owningType,
            bool isTopLevel,
            bool allowStreamProperty,
            IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
        {
            WriterValidationUtils.ValidatePropertyNotNull(property);

            string propertyName = property.Name;

            if (this.JsonLightOutputContext.MessageWriterSettings.Validations != ValidationKinds.None)
            {
                WriterValidationUtils.ValidatePropertyName(propertyName);
            }

            if (!this.JsonLightOutputContext.PropertyCacheHandler.InResourceSetScope())
            {
                this.currentPropertyInfo = new PropertySerializationInfo(propertyName, owningType)
                {
                    IsTopLevel = isTopLevel
                };
            }
            else
            {
                this.currentPropertyInfo = this.JsonLightOutputContext.PropertyCacheHandler.GetProperty(propertyName, owningType);
            }

            WriterValidationUtils.ValidatePropertyDefined(this.currentPropertyInfo, this.MessageWriterSettings.ThrowOnUndeclaredPropertyForNonOpenType);

            duplicatePropertyNameChecker.ValidatePropertyUniqueness(property);

            if (currentPropertyInfo.MetadataType.IsUndeclaredProperty)
            {
                WriteODataTypeAnnotation(property, isTopLevel);
            }

            WriteInstanceAnnotation(property, isTopLevel, currentPropertyInfo.MetadataType.IsUndeclaredProperty);

            ODataValue value = property.ODataValue;

            // handle ODataUntypedValue
            ODataUntypedValue untypedValue = value as ODataUntypedValue;

            if (untypedValue != null)
            {
                WriteUntypedValue(untypedValue);
                return;
            }

            ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue;

            if (streamReferenceValue != null)
            {
                if (!allowStreamProperty)
                {
                    throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataResource(propertyName));
                }

                Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type.");
                Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level.");
                WriterValidationUtils.ValidateStreamReferenceProperty(property, currentPropertyInfo.MetadataType.EdmProperty, this.WritingResponse);
                this.WriteStreamReferenceProperty(propertyName, streamReferenceValue);
                return;
            }

            if (value is ODataNullValue || value == null)
            {
                this.WriteNullProperty(property);
                return;
            }

            bool isOpenPropertyType = this.IsOpenProperty(property);

            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                this.WritePrimitiveProperty(primitiveValue, isOpenPropertyType);
                return;
            }

            ODataEnumValue enumValue = value as ODataEnumValue;

            if (enumValue != null)
            {
                this.WriteEnumProperty(enumValue, isOpenPropertyType);
                return;
            }

            ODataCollectionValue collectionValue = value as ODataCollectionValue;

            if (collectionValue != null)
            {
                this.WriteCollectionProperty(collectionValue, isOpenPropertyType);
                return;
            }
        }
コード例 #11
0
        /// <summary>
        /// Writes the navigation link metadata.
        /// </summary>
        /// <param name="nestedResourceInfo">The navigation link to write the metadata for.</param>
        /// <param name="duplicatePropertyNameChecker">The DuplicatePropertyNameChecker to use.</param>
        internal void WriteNavigationLinkMetadata(ODataNestedResourceInfo nestedResourceInfo, IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
        {
            Debug.Assert(nestedResourceInfo != null, "nestedResourceInfo != null");
            Debug.Assert(!string.IsNullOrEmpty(nestedResourceInfo.Name), "The nested resource info Name should have been validated by now.");
            Debug.Assert(duplicatePropertyNameChecker != null);

            Uri    navigationLinkUrl  = nestedResourceInfo.Url;
            string navigationLinkName = nestedResourceInfo.Name;
            Uri    associationLinkUrl = nestedResourceInfo.AssociationLinkUrl;

            if (associationLinkUrl != null)
            {
                duplicatePropertyNameChecker.ValidatePropertyOpenForAssociationLink(navigationLinkName);
                this.WriteAssociationLink(nestedResourceInfo.Name, associationLinkUrl);
            }

            if (navigationLinkUrl != null)
            {
                // The navigation link URL is a property annotation "[email protected]: 'url'"
                this.ODataAnnotationWriter.WritePropertyAnnotationName(navigationLinkName, ODataAnnotationNames.ODataNavigationLinkUrl);
                this.JsonWriter.WriteValue(this.UriToString(navigationLinkUrl));
            }
        }
コード例 #12
0
        /// <summary>
        /// Writes the metadata properties for a resource which can only occur at the end.
        /// </summary>
        /// <param name="resourceState">The resource state for which to write the metadata properties.</param>
        /// <param name="duplicatePropertyNameChecker">The DuplicatePropertyNameChecker to use.</param>
        internal void WriteResourceEndMetadataProperties(IODataJsonLightWriterResourceState resourceState, IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
        {
            Debug.Assert(resourceState != null, "resourceState != null");

            ODataResourceBase resource = resourceState.Resource;

            // write computed navigation properties
            var navigationLinkInfo = resource.MetadataBuilder.GetNextUnprocessedNavigationLink();

            while (navigationLinkInfo != null)
            {
                Debug.Assert(resource.MetadataBuilder != null, "resource.MetadataBuilder != null");
                navigationLinkInfo.NestedResourceInfo.MetadataBuilder = resource.MetadataBuilder;

                this.WriteNavigationLinkMetadata(navigationLinkInfo.NestedResourceInfo, duplicatePropertyNameChecker);
                navigationLinkInfo = resource.MetadataBuilder.GetNextUnprocessedNavigationLink();
            }

            // write computed stream properties
            ODataProperty streamProperty = resource.MetadataBuilder.GetNextUnprocessedStreamProperty();

            while (streamProperty != null)
            {
                this.WriteProperty(streamProperty, resourceState.ResourceType, /*isTopLevel*/ false, duplicatePropertyNameChecker, null /*metadataBuilder*/);
                streamProperty = resource.MetadataBuilder.GetNextUnprocessedStreamProperty();
            }

            // write "odata.actions" metadata
            IEnumerable <ODataAction> actions = resource.Actions;

            if (actions != null && actions.Any())
            {
                this.WriteOperations(actions.Cast <ODataOperation>(), /*isAction*/ true);
            }

            // write "odata.functions" metadata
            IEnumerable <ODataFunction> functions = resource.Functions;

            if (functions != null && functions.Any())
            {
                this.WriteOperations(functions.Cast <ODataOperation>(), /*isAction*/ false);
            }
        }
コード例 #13
0
 public override void WriteResourceValue(ODataResourceValue resourceValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, IDuplicatePropertyNameChecker duplicatePropertyNamesChecker)
 {
     Assert.NotNull(this.WriteResourceValueVerifier);
     this.WriteResourceValueVerifier(resourceValue, metadataTypeReference, isOpenPropertyType, duplicatePropertyNamesChecker);
 }
コード例 #14
0
 public override void WriteResourceValue(ODataResourceValue resourceValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, IDuplicatePropertyNameChecker duplicatePropertyNamesChecker)
 {
     this.WriteResourceValueVerifier.Should().NotBeNull("WriteResourceValue was called.");
     this.WriteResourceValueVerifier(resourceValue, metadataTypeReference, isOpenPropertyType, duplicatePropertyNamesChecker);
 }
コード例 #15
0
ファイル: ODataSerializer.cs プロジェクト: ificator/odata.net
 /// <summary>
 /// Returns an instance of a duplicate property names checker to the object pool.
 /// </summary>
 internal void ReturnDuplicatePropertyNameChecker(IDuplicatePropertyNameChecker duplicatePropertyNameChecker)
 {
     MessageWriterSettings.Validator.ReturnDuplicatePropertyNameChecker(duplicatePropertyNameChecker);
 }