コード例 #1
0
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="complexType">The EDM complex type of the object.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType,
                                                                 ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null || graph is NullEdmComplexObject)
            {
                return(null);
            }

            IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model);

            List <ODataProperty> propertyCollection = new List <ODataProperty>();

            foreach (IEdmProperty property in complexType.ComplexDefinition().Properties())
            {
                IEdmTypeReference      propertyType       = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name);
                }

                object propertyValue;
                if (complexObject.TryGetPropertyValue(property.Name, out propertyValue))
                {
                    propertyCollection.Add(
                        propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext));
                }
            }

            // Try to add the dynamic properties if the complex type is open.
            if (complexType.ComplexDefinition().IsOpen)
            {
                List <ODataProperty> dynamicProperties =
                    AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]);

                if (dynamicProperties != null)
                {
                    propertyCollection.AddRange(dynamicProperties);
                }
            }

            string typeName = complexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName   = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return(value);
        }
コード例 #2
0
        internal void WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            this.IncreaseRecursionDepth();
            base.JsonWriter.StartObjectScope();
            string typeName = complexValue.TypeName;

            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
            }
            IEdmComplexTypeReference type = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, propertyTypeReference, 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;
            }
            if (typeName != null)
            {
                base.JsonWriter.WriteName("__metadata");
                base.JsonWriter.StartObjectScope();
                base.JsonWriter.WriteName("type");
                base.JsonWriter.WriteValue(typeName);
                base.JsonWriter.EndObjectScope();
            }
            this.WriteProperties((type == null) ? null : type.ComplexDefinition(), complexValue.Properties, true, duplicatePropertyNamesChecker, null);
            base.JsonWriter.EndObjectScope();
            this.DecreaseRecursionDepth();
        }
コード例 #3
0
        public override ODataProperty CreateProperty(object graph, string elementName, ODataSerializerWriteContext writeContext)
        {
            if (String.IsNullOrWhiteSpace(elementName))
            {
                throw Error.ArgumentNullOrEmpty("elementName");
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            List <ODataProperty> propertyCollection = null;

            if (graph != null)
            {
                propertyCollection = new List <ODataProperty>();
                foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties())
                {
                    IEdmTypeReference propertyType       = property.Type;
                    ODataSerializer   propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                    if (propertySerializer == null)
                    {
                        throw Error.NotSupported("Type {0} is not a serializable type", propertyType.FullName());
                    }

                    // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter.
                    object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null);

                    propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext));
                }
            }

            if (propertyCollection != null)
            {
                return(new ODataProperty()
                {
                    Name = elementName,
                    Value = new ODataComplexValue()
                    {
                        Properties = propertyCollection,
                        TypeName = _edmComplexType.FullName()
                    }
                });
            }
            else
            {
                return(null);
            }
        }
コード例 #4
0
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="propertyTypeReference">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param>
        /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param>
        /// <param name="collectionValidator">The collection validator instance to validate the type names and type kinds of collection items; null if no validation is needed.</param>
        /// <remarks>The current recursion depth should be a value, measured by the number of complex and collection values between
        /// this complex value and the top-level payload, not including this one.</remarks>
        internal void WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference propertyTypeReference,
            bool isOpenPropertyType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire complex instance
            this.JsonWriter.StartObjectScope();

            string typeName = complexValue.TypeName;

            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
            }

            // resolve the type name to the type; if no type name is specified we will use the type inferred from metadata
            IEdmComplexTypeReference complexValueTypeReference = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, complexValue, isOpenPropertyType).AsComplexOrNull();

            string collectionItemTypeName;

            typeName = this.VerboseJsonOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, complexValueTypeReference, complexValue.GetAnnotation <SerializationTypeNameAnnotation>(), collectionValidator, out collectionItemTypeName);
            Debug.Assert(collectionItemTypeName == null, "collectionItemTypeName == null");

            // Write the "__metadata" : { "type": "typename" }
            // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely
            if (typeName != null)
            {
                ODataJsonWriterUtils.WriteMetadataWithTypeName(this.JsonWriter, typeName);
            }

            // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties.
            this.WriteProperties(
                complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(),
                complexValue.Properties,
                true /* isComplexValue */,
                duplicatePropertyNamesChecker,
                null /*projectedProperties */);

            // End the object scope which represents the complex instance
            this.JsonWriter.EndObjectScope();

            this.DecreaseRecursionDepth();
        }
コード例 #5
0
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual ODataComplexValue CreateODataComplexValue(object graph, ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null)
            {
                return(null);
            }

            List <ODataProperty> propertyCollection = new List <ODataProperty>();

            foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties())
            {
                IEdmTypeReference      propertyType       = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name);
                }

                // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter.
                object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null);

                propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext));
            }

            string typeName = _edmComplexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName   = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return(value);
        }
コード例 #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class.
 /// </summary>
 /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param>
 public EdmComplexObject(IEdmComplexTypeReference edmType)
     : this(edmType.ComplexDefinition(), edmType.IsNullable)
 {
 }
コード例 #7
0
        /// <summary>
        /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>.
        /// </summary>
        /// <param name="complexValue">The complex value to deserialize.</param>
        /// <param name="complexType">The EDM type of the complex value to read.</param>
        /// <param name="readContext">The deserializer context.</param>
        /// <returns>The deserialized complex value.</returns>
        public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType,
                                               ODataDeserializerContext readContext)
        {
            if (complexValue == null)
            {
                throw Error.ArgumentNull("complexValue");
            }

            if (readContext == null)
            {
                throw Error.ArgumentNull("readContext");
            }

            if (readContext.Model == null)
            {
                throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext);
            }

            if (!String.IsNullOrEmpty(complexValue.TypeName) && complexType.FullName() != complexValue.TypeName)
            {
                // received a derived complex type in a base type deserializer.
                IEdmModel model = readContext.Model;
                if (model == null)
                {
                    throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext);
                }

                IEdmComplexType actualType = model.FindType(complexValue.TypeName) as IEdmComplexType;
                if (actualType == null)
                {
                    throw new ODataException(Error.Format(SRResources.ComplexTypeNotInModel, complexValue.TypeName));
                }

                if (actualType.IsAbstract)
                {
                    string message = Error.Format(SRResources.CannotInstantiateAbstractComplexType,
                                                  complexValue.TypeName);
                    throw new ODataException(message);
                }

                IEdmTypeReference        actualComplexType = new EdmComplexTypeReference(actualType, isNullable: false);
                ODataEdmTypeDeserializer deserializer      = DeserializerProvider.GetEdmTypeDeserializer(actualComplexType);
                if (deserializer == null)
                {
                    throw new SerializationException(
                              Error.Format(SRResources.TypeCannotBeDeserialized, actualComplexType.FullName(),
                                           typeof(ODataMediaTypeFormatter).Name));
                }

                object resource = deserializer.ReadInline(complexValue, actualComplexType, readContext);

                EdmStructuredObject structuredObject = resource as EdmStructuredObject;
                if (structuredObject != null)
                {
                    structuredObject.ExpectedEdmType = complexType.ComplexDefinition();
                }

                return(resource);
            }
            else
            {
                object complexResource = CreateResource(complexType, readContext);

                foreach (ODataProperty complexProperty in complexValue.Properties)
                {
                    DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource,
                                                         DeserializerProvider, readContext);
                }
                return(complexResource);
            }
        }
コード例 #8
0
        /// <summary>
        /// Deserializes the given <paramref name="complexValue"/> under the given <paramref name="readContext"/>.
        /// </summary>
        /// <param name="complexValue">The complex value to deserialize.</param>
        /// <param name="complexType">The EDM type of the complex value to read.</param>
        /// <param name="readContext">The deserializer context.</param>
        /// <returns>The deserialized complex value.</returns>
        public virtual object ReadComplexValue(ODataComplexValue complexValue, IEdmComplexTypeReference complexType,
            ODataDeserializerContext readContext)
        {
            if (complexValue == null)
            {
                throw Error.ArgumentNull("complexValue");
            }

            if (readContext == null)
            {
                throw Error.ArgumentNull("readContext");
            }

            if (readContext.Model == null)
            {
                throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext);
            }

            if (!String.IsNullOrEmpty(complexValue.TypeName) && complexType.FullName() != complexValue.TypeName)
            {
                // received a derived complex type in a base type deserializer.
                IEdmModel model = readContext.Model;
                if (model == null)
                {
                    throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext);
                }

                IEdmComplexType actualType = model.FindType(complexValue.TypeName) as IEdmComplexType;
                if (actualType == null)
                {
                    throw new ODataException(Error.Format(SRResources.ComplexTypeNotInModel, complexValue.TypeName));
                }

                if (actualType.IsAbstract)
                {
                    string message = Error.Format(SRResources.CannotInstantiateAbstractComplexType,
                        complexValue.TypeName);
                    throw new ODataException(message);
                }

                IEdmTypeReference actualComplexType = new EdmComplexTypeReference(actualType, isNullable: false);
                ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(actualComplexType);
                if (deserializer == null)
                {
                    throw new SerializationException(
                        Error.Format(SRResources.TypeCannotBeDeserialized, actualComplexType.FullName(),
                            typeof(ODataMediaTypeFormatter).Name));
                }

                object resource = deserializer.ReadInline(complexValue, actualComplexType, readContext);

                EdmStructuredObject structuredObject = resource as EdmStructuredObject;
                if (structuredObject != null)
                {
                    structuredObject.ExpectedEdmType = complexType.ComplexDefinition();
                }

                return resource;
            }
            else
            {
                object complexResource = CreateResource(complexType, readContext);

                foreach (ODataProperty complexProperty in complexValue.Properties)
                {
                    DeserializationHelpers.ApplyProperty(complexProperty, complexType, complexResource,
                        DeserializerProvider, readContext);
                }
                return complexResource;
            }
        }
コード例 #9
0
 private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
 {
     this.IncreaseRecursionDepth();
     base.JsonReader.ReadStartObject();
     ODataComplexValue value2 = new ODataComplexValue {
         TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName
     };
     if (serializationTypeNameAnnotation != null)
     {
         value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation);
     }
     if (duplicatePropertyNamesChecker == null)
     {
         duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
     }
     else
     {
         duplicatePropertyNamesChecker.Clear();
     }
     List<ODataProperty> sourceList = new List<ODataProperty>();
     bool flag = false;
     while (base.JsonReader.NodeType == JsonNodeType.Property)
     {
         string strB = base.JsonReader.ReadPropertyName();
         if (string.CompareOrdinal("__metadata", strB) == 0)
         {
             if (flag)
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue);
             }
             flag = true;
             base.JsonReader.SkipValue();
         }
         else if (!ValidationUtils.IsValidPropertyName(strB))
         {
             base.JsonReader.SkipValue();
         }
         else
         {
             ODataProperty property = new ODataProperty {
                 Name = strB
             };
             IEdmProperty property2 = null;
             bool ignoreProperty = false;
             if (complexValueTypeReference != null)
             {
                 property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty);
             }
             if (ignoreProperty)
             {
                 base.JsonReader.SkipValue();
                 continue;
             }
             ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2);
             object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default);
             if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null))
             {
                 duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                 property.Value = obj2;
                 sourceList.Add(property);
             }
         }
     }
     base.JsonReader.ReadEndObject();
     value2.Properties = new ReadOnlyEnumerable<ODataProperty>(sourceList);
     this.DecreaseRecursionDepth();
     return value2;
 }
コード例 #10
0
        internal void AppendDynamicProperties(object graph, IEdmComplexTypeReference complexType,
            ODataSerializerContext writeContext, List<ODataProperty> propertyCollection)
        {
            PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(complexType.ComplexDefinition(),
                writeContext.Model);

            if (dynamicPropertyInfo != null)
            {
                IDictionary<string, object> dynamicPropertyDictionary = dynamicPropertyInfo.GetValue(graph)
                    as IDictionary<string, object>;

                if (dynamicPropertyDictionary != null)
                {
                    // build a HashSet to store the declared property names.
                    // It is used to make sure the dynamic property name is different with the declared property name.
                    HashSet<string> declaredPropertyNameSet = new HashSet<string>(propertyCollection.Select(a => a.Name));

                    foreach (KeyValuePair<string, object> dynamicProperty in dynamicPropertyDictionary)
                    {
                        if (dynamicProperty.Value == null)
                        {
                            continue; // skip the null object
                        }

                        Type valueType = dynamicProperty.Value.GetType();
                        IEdmTypeReference edmTypeReference = writeContext.Model.GetEdmTypeReference(valueType);
                        ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference);
                        if (propertySerializer == null)
                        {
                            throw Error.NotSupported(SRResources.TypeCannotBeSerialized,
                                valueType.FullName, typeof(ODataComplexTypeSerializer).Name);
                        }

                        // try to make sure the dynamic property name is not used as declared property name.
                        if (declaredPropertyNameSet.Contains(dynamicProperty.Key))
                        {
                            throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName,
                                dynamicProperty.Key, complexType.FullName());
                        }

                        propertyCollection.Add(propertySerializer.CreateProperty(
                            dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext));
                    }
                }
            }
        }
コード例 #11
0
        /// <summary>
        /// Reads a complex value.
        /// </summary>
        /// <param name="complexValueTypeReference">The expected type reference of the value.</param>
        /// <param name="payloadTypeName">The type name read from the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param>
        /// <returns>The value of the complex value.</returns>
        /// <remarks>
        /// Pre-Condition:  Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value)
        /// Post-Condition: almost anything - the node after the complex value (after the EndObject)
        /// </remarks>
        private ODataComplexValue ReadComplexValueImplementation(
            IEdmComplexTypeReference complexValueTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.JsonReader.AssertNotBuffering();

            this.IncreaseRecursionDepth();

            // Read over the start object
            this.JsonReader.ReadStartObject();

            ODataComplexValue complexValue = new ODataComplexValue();

            complexValue.TypeName = complexValueTypeReference != null?complexValueTypeReference.ODataFullName() : payloadTypeName;

            if (serializationTypeNameAnnotation != null)
            {
                complexValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
            }
            else
            {
                duplicatePropertyNamesChecker.Clear();
            }

            List <ODataProperty> properties = new List <ODataProperty>();
            bool metadataPropertyFound      = false;

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();
                if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0)
                {
                    // __metadata property.
                    if (metadataPropertyFound)
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue);
                    }

                    metadataPropertyFound = true;

                    this.JsonReader.SkipValue();
                }
                else
                {
                    if (!ValidationUtils.IsValidPropertyName(propertyName))
                    {
                        // We ignore properties with an invalid name since these are extension points for the future.
                        this.JsonReader.SkipValue();
                    }
                    else
                    {
                        // Any other property is data
                        ODataProperty property = new ODataProperty();
                        property.Name = propertyName;

                        // Lookup the property in metadata
                        IEdmProperty edmProperty    = null;
                        bool         ignoreProperty = false;
                        if (complexValueTypeReference != null)
                        {
                            edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty);
                        }

                        if (ignoreProperty)
                        {
                            // in case of ignoreProperty = true which means to ignore undeclared property.
                            this.JsonReader.SkipValue();
                        }
                        else
                        {
                            ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null
                                ? ODataNullValueBehaviorKind.Default
                                : this.Model.NullValueReadBehaviorKind(edmProperty);

                            // Read the property value
                            object propertyValue = this.ReadNonEntityValueImplementation(
                                edmProperty == null ? null : edmProperty.Type,
                                /*duplicatePropertyNamesChecker*/ null,
                                /*collectionValidator*/ null,
                                nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default,
                                propertyName);

                            if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null)
                            {
                                duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                                property.Value = propertyValue;
                                properties.Add(property);
                            }
                        }
                    }
                }
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected.");
            this.JsonReader.ReadEndObject();

            complexValue.Properties = new ReadOnlyEnumerable <ODataProperty>(properties);

            this.JsonReader.AssertNotBuffering();
            this.DecreaseRecursionDepth();

            return(complexValue);
        }
コード例 #12
0
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="complexType">The EDM complex type of the object.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType,
            ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null || graph is NullEdmComplexObject)
            {
                return null;
            }

            IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType);

            List<ODataProperty> propertyCollection = new List<ODataProperty>();
            foreach (IEdmProperty property in complexType.ComplexDefinition().Properties())
            {
                IEdmTypeReference propertyType = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name);
                }

                object propertyValue;
                if (complexObject.TryGetPropertyValue(property.Name, out propertyValue))
                {
                    propertyCollection.Add(
                        propertySerializer.CreateProperty(propertyValue, property.Type, property.Name, writeContext));
                }
            }

            string typeName = complexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return value;
        }
コード例 #13
0
ファイル: EdmComplexObject.cs プロジェクト: ldcdev/WebApi
 /// <summary>
 /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class.
 /// </summary>
 /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param>
 /// <param name="assembliesResolver">The assemblies resolve to use for type resolution</param>
 public EdmComplexObject(IEdmComplexTypeReference edmType, AssembliesResolver assembliesResolver)
     : this(edmType.ComplexDefinition(), assembliesResolver, edmType.IsNullable)
 {
 }
コード例 #14
0
 public void CreateResource_Throws_MappingDoesNotContainEntityType()
 {
     Assert.Throws <InvalidOperationException>(
         () => ODataComplexTypeDeserializer.CreateResource(_addressEdmType.ComplexDefinition(), EdmCoreModel.Instance),
         "The provided mapping doesn't contain an entry for the entity type 'ODataDemo.Address'.");
 }
コード例 #15
0
        private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.IncreaseRecursionDepth();
            base.JsonReader.ReadStartObject();
            ODataComplexValue value2 = new ODataComplexValue {
                TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName
            };

            if (serializationTypeNameAnnotation != null)
            {
                value2.SetAnnotation <SerializationTypeNameAnnotation>(serializationTypeNameAnnotation);
            }
            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker();
            }
            else
            {
                duplicatePropertyNamesChecker.Clear();
            }
            List <ODataProperty> sourceList = new List <ODataProperty>();
            bool flag = false;

            while (base.JsonReader.NodeType == JsonNodeType.Property)
            {
                string strB = base.JsonReader.ReadPropertyName();
                if (string.CompareOrdinal("__metadata", strB) == 0)
                {
                    if (flag)
                    {
                        throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue);
                    }
                    flag = true;
                    base.JsonReader.SkipValue();
                }
                else if (!ValidationUtils.IsValidPropertyName(strB))
                {
                    base.JsonReader.SkipValue();
                }
                else
                {
                    ODataProperty property = new ODataProperty {
                        Name = strB
                    };
                    IEdmProperty property2      = null;
                    bool         ignoreProperty = false;
                    if (complexValueTypeReference != null)
                    {
                        property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty);
                    }
                    if (ignoreProperty)
                    {
                        base.JsonReader.SkipValue();
                        continue;
                    }
                    ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2);
                    object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default);
                    if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null))
                    {
                        duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                        property.Value = obj2;
                        sourceList.Add(property);
                    }
                }
            }
            base.JsonReader.ReadEndObject();
            value2.Properties = new ReadOnlyEnumerable <ODataProperty>(sourceList);
            this.DecreaseRecursionDepth();
            return(value2);
        }
コード例 #16
0
        internal bool WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference metadataTypeReference,
            bool isOpenPropertyType,
            bool isWritingCollection,
            Action beforeValueAction,
            Action afterValueAction,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            ProjectedPropertiesAnnotation projectedProperties)
        {
            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.ResolveAndValidateTypeForComplexValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType, this.WriterValidator).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);
                }
            }

            bool propertyWritten = this.WriteProperties(
                complexTypeReference == null ? null : complexTypeReference.ComplexDefinition(),
                complexValue.Properties,
                isWritingCollection,
                beforeValueCallbackWithTypeName,
                afterValueAction,
                duplicatePropertyNamesChecker,
                projectedProperties);

            this.DecreaseRecursionDepth();
            return(propertyWritten);
        }
コード例 #17
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);
        }
コード例 #18
0
        /// <summary>
        /// Reads a complex value.
        /// </summary>
        /// <param name="complexValueTypeReference">The expected type reference of the value.</param>
        /// <param name="payloadTypeName">The type name read from the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param>
        /// <returns>The value of the complex value.</returns>
        /// <remarks>
        /// Pre-Condition:  Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value)
        /// Post-Condition: almost anything - the node after the complex value (after the EndObject)
        /// </remarks>
        private ODataComplexValue ReadComplexValueImplementation(
            IEdmComplexTypeReference complexValueTypeReference, 
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.JsonReader.AssertNotBuffering();

            this.IncreaseRecursionDepth();

            // Read over the start object
            this.JsonReader.ReadStartObject();

            ODataComplexValue complexValue = new ODataComplexValue();

            complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.ODataFullName() : payloadTypeName; 
            if (serializationTypeNameAnnotation != null)
            {
                complexValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            if (duplicatePropertyNamesChecker == null)
            {
                duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker();
            }
            else
            {
                duplicatePropertyNamesChecker.Clear();
            }

            List<ODataProperty> properties = new List<ODataProperty>();
            bool metadataPropertyFound = false;
            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();
                if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0)
                {
                    // __metadata property.
                    if (metadataPropertyFound)
                    {
                        throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue);
                    }

                    metadataPropertyFound = true;

                    this.JsonReader.SkipValue();
                }
                else
                {
                    if (!ValidationUtils.IsValidPropertyName(propertyName))
                    {
                        // We ignore properties with an invalid name since these are extension points for the future.
                        this.JsonReader.SkipValue();
                    }
                    else
                    {
                        // Any other property is data
                        ODataProperty property = new ODataProperty();
                        property.Name = propertyName;

                        // Lookup the property in metadata
                        IEdmProperty edmProperty = null;
                        bool ignoreProperty = false;
                        if (complexValueTypeReference != null)
                        {
                            edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty);
                        }

                        if (ignoreProperty)
                        {
                            this.JsonReader.SkipValue();
                        }
                        else
                        {
                            ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null
                                ? ODataNullValueBehaviorKind.Default
                                : this.Model.NullValueReadBehaviorKind(edmProperty);

                            // Read the property value
                            object propertyValue = this.ReadNonEntityValueImplementation(
                                edmProperty == null ? null : edmProperty.Type,
                                /*duplicatePropertyNamesChecker*/ null,
                                /*collectionValidator*/ null,
                                nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default);

                            if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null)
                            {
                                duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                                property.Value = propertyValue;
                                properties.Add(property);
                            }
                        }
                    }
                }
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected.");
            this.JsonReader.ReadEndObject();

            complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties);

            this.JsonReader.AssertNotBuffering();
            this.DecreaseRecursionDepth();

            return complexValue;
        }
コード例 #19
0
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="complexType">The EDM complex type of the object.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType,
                                                                 ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null || graph is NullEdmComplexObject)
            {
                return(null);
            }

            IEdmComplexObject   complexObject      = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model);
            List <IEdmProperty> settableProperties = new List <IEdmProperty>(complexType.ComplexDefinition().Properties());

            if (complexObject.IsDeltaResource())
            {
                IDelta deltaProperty = graph as IDelta;
                Contract.Assert(deltaProperty != null);
                IEnumerable <string> changedProperties = deltaProperty.GetChangedPropertyNames();
                settableProperties = settableProperties.Where(p => changedProperties.Contains(p.Name)).ToList();
            }
            List <ODataProperty> propertyCollection = new List <ODataProperty>();

            foreach (IEdmProperty property in settableProperties)
            {
                IEdmTypeReference      propertyType       = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataMediaTypeFormatter).Name);
                }

                object propertyValue;
                if (complexObject.TryGetPropertyValue(property.Name, out propertyValue))
                {
                    if (propertyValue != null && propertyType != null && propertyType.IsComplex())
                    {
                        IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType());
                        if (actualType != null && propertyType != actualType)
                        {
                            propertyType = actualType;
                        }
                    }
                    var odataProperty = propertySerializer.CreateProperty(propertyValue, propertyType, property.Name,
                                                                          writeContext);
                    if (odataProperty != null)
                    {
                        propertyCollection.Add(odataProperty);
                    }
                }
            }

            // Try to add the dynamic properties if the complex type is open.
            if (complexType.ComplexDefinition().IsOpen)
            {
                List <ODataProperty> dynamicProperties =
                    AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]);

                if (dynamicProperties != null)
                {
                    propertyCollection.AddRange(dynamicProperties);
                }
            }

            string typeName = complexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName   = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return(value);
        }
コード例 #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="EdmStructuredObject"/> class.
 /// </summary>
 /// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param>
 public EdmComplexObject(IEdmComplexTypeReference edmType)
     : this(edmType.ComplexDefinition(), edmType.IsNullable)
 {
 }
コード例 #21
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);
        }
コード例 #22
0
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="complexType">The EDM complex type of the object.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType,
            ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null || graph is NullEdmComplexObject)
            {
                return null;
            }

            IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model);

            List<ODataProperty> propertyCollection = new List<ODataProperty>();
            foreach (IEdmProperty property in complexType.ComplexDefinition().Properties())
            {
                IEdmTypeReference propertyType = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataOutputFormatter).Name);
                }

                object propertyValue;
                if (complexObject.TryGetPropertyValue(property.Name, out propertyValue))
                {
                    if (propertyType != null && propertyType.IsComplex())
                    {
                        IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType());
                        if (actualType != null && propertyType != actualType)
                        {
                            propertyType = actualType;
                        }
                    }

                    propertyCollection.Add(
                        propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext));
                }
            }

            // Try to add the dynamic properties if the complex type is open.
            if (complexType.ComplexDefinition().IsOpen)
            {
                List<ODataProperty> dynamicProperties =
                    AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]);

                if (dynamicProperties != null)
                {
                    propertyCollection.AddRange(dynamicProperties);
                }
            }

            string typeName = complexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return value;
        }
コード例 #23
0
        public void WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference metadataTypeReference,
            bool isTopLevel,
            bool isOpenPropertyType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(complexValue != null, "complexValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire complex instance;
            // for top-level complex properties we already wrote the object scope (and the context URI when needed).
            if (!isTopLevel)
            {
                this.JsonWriter.StartObjectScope();
            }

            string typeName = complexValue.TypeName;

            if (isTopLevel)
            {
                Debug.Assert(metadataTypeReference == null, "Never expect a metadata type for top-level properties.");
                if (typeName == null)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightValueSerializer_MissingTypeNameOnComplex);
                }
            }
            else
            {
                // 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_NoExpectedTypeOrTypeNameSpecifiedForComplexValueRequest);
                }
            }

            // Resolve the type name to the type; if no type name is specified we will use the
            // type inferred from metadata.
            IEdmComplexTypeReference complexValueTypeReference = (IEdmComplexTypeReference)TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, metadataTypeReference, complexValue, isOpenPropertyType);

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

            typeName = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(complexValue, metadataTypeReference, complexValueTypeReference, isOpenPropertyType);
            if (typeName != null)
            {
                ODataJsonLightWriterUtils.WriteODataTypeInstanceAnnotation(this.JsonWriter, typeName);
            }

            // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties.
            this.PropertySerializer.WriteProperties(
                complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(),
                complexValue.Properties,
                true /* isComplexValue */,
                duplicatePropertyNamesChecker,
                null /*projectedProperties */);

            // End the object scope which represents the complex instance;
            // for top-level complex properties we already wrote the end object scope.
            if (!isTopLevel)
            {
                this.JsonWriter.EndObjectScope();
            }

            this.DecreaseRecursionDepth();
        }
コード例 #24
0
        internal void AppendDynamicProperties(object graph, IEdmComplexTypeReference complexType,
                                              ODataSerializerContext writeContext, List <ODataProperty> propertyCollection)
        {
            PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(complexType.ComplexDefinition(),
                                                                                          writeContext.Model);

            if (dynamicPropertyInfo != null)
            {
                IDictionary <string, object> dynamicPropertyDictionary = dynamicPropertyInfo.GetValue(graph)
                                                                         as IDictionary <string, object>;

                if (dynamicPropertyDictionary != null)
                {
                    // build a HashSet to store the declared property names.
                    // It is used to make sure the dynamic property name is different with the declared property name.
                    HashSet <string> declaredPropertyNameSet = new HashSet <string>(propertyCollection.Select(a => a.Name));

                    foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertyDictionary)
                    {
                        if (dynamicProperty.Value == null)
                        {
                            continue; // skip the null object
                        }

                        Type valueType = dynamicProperty.Value.GetType();
                        IEdmTypeReference      edmTypeReference   = writeContext.Model.GetEdmTypeReference(valueType);
                        ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference);
                        if (propertySerializer == null)
                        {
                            throw Error.NotSupported(SRResources.TypeCannotBeSerialized,
                                                     valueType.FullName, typeof(ODataComplexTypeSerializer).Name);
                        }

                        // try to make sure the dynamic property name is not used as declared property name.
                        if (declaredPropertyNameSet.Contains(dynamicProperty.Key))
                        {
                            throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName,
                                                         dynamicProperty.Key, complexType.FullName());
                        }

                        propertyCollection.Add(propertySerializer.CreateProperty(
                                                   dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext));
                    }
                }
            }
        }
        /// <summary>
        /// Reads a complex value.
        /// </summary>
        /// <param name="complexValueTypeReference">The expected type reference of the value.</param>
        /// <param name="payloadTypeName">The type name read from the payload.</param>
        /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - this is always initialized as necessary, do not clear.</param>
        /// <returns>The value of the complex value.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.Property - the first property of the complex value object, or the second one if the first one was odata.type.
        ///                 JsonNodeType.EndObject - the end object of the complex value object.
        /// Post-Condition: almost anything - the node after the complex value (after the EndObject)
        /// </remarks>
        private ODataComplexValue ReadComplexValue(
            IEdmComplexTypeReference complexValueTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);
            Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");

            this.IncreaseRecursionDepth();

            ODataComplexValue complexValue = new ODataComplexValue();
            complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.FullName() : payloadTypeName;
            if (serializationTypeNameAnnotation != null)
            {
                complexValue.SetAnnotation(serializationTypeNameAnnotation);
            }

            if (complexValueTypeReference != null)
            {
                complexValue.SetAnnotation(new ODataTypeAnnotation(complexValueTypeReference));
            }

            List<ODataProperty> properties = new List<ODataProperty>();
            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                this.ReadPropertyCustomAnnotationValue = this.ReadCustomInstanceAnnotationValue;
                this.ProcessProperty(
                    duplicatePropertyNamesChecker,
                    this.ReadTypePropertyAnnotationValue,
                    (propertyParsingResult, propertyName) =>
                    {
                        switch (propertyParsingResult)
                        {
                            case PropertyParsingResult.ODataInstanceAnnotation:
                                if (string.CompareOrdinal(ODataAnnotationNames.ODataType, propertyName) == 0)
                                {
                                    throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexTypeAnnotationNotFirst);
                                }
                                else
                                {
                                    throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedAnnotationProperties(propertyName));
                                }

                            case PropertyParsingResult.CustomInstanceAnnotation:
                                ODataAnnotationNames.ValidateIsCustomAnnotationName(propertyName);
                                Debug.Assert(
                                    !this.MessageReaderSettings.ShouldSkipAnnotation(propertyName),
                                    "!this.MessageReaderSettings.ShouldReadAndValidateAnnotation(annotationName) -- otherwise we should have already skipped the custom annotation and won't see it here.");
                                var customInstanceAnnotationValue = this.ReadCustomInstanceAnnotationValue(duplicatePropertyNamesChecker, propertyName);
                                complexValue.InstanceAnnotations.Add(new ODataInstanceAnnotation(propertyName, customInstanceAnnotationValue.ToODataValue()));
                                break;

                            case PropertyParsingResult.PropertyWithoutValue:
                                throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_ComplexValuePropertyAnnotationWithoutProperty(propertyName));

                            case PropertyParsingResult.PropertyWithValue:
                                // Any other property is data
                                ODataProperty property = new ODataProperty();
                                property.Name = propertyName;

                                // Lookup the property in metadata
                                IEdmProperty edmProperty = null;
                                bool ignoreProperty = false;
                                if (complexValueTypeReference != null)
                                {
                                    edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty);
                                }

                                if (ignoreProperty
                                    && (this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray))
                                {
                                    this.JsonReader.SkipValue();
                                }
                                else
                                {
                                    // EdmLib bridge marks all key properties as non-nullable, but Astoria allows them to be nullable.
                                    // If the property has an annotation to ignore null values, we need to omit the property in requests.
                                    ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null
                                        ? ODataNullValueBehaviorKind.Default
                                        : this.Model.NullValueReadBehaviorKind(edmProperty);

                                    // Read the property value
                                    object propertyValue = this.ReadNonEntityValueImplementation(
                                        ValidateDataPropertyTypeNameAnnotation(duplicatePropertyNamesChecker, propertyName),
                                        edmProperty == null ? null : edmProperty.Type,
                                        /*duplicatePropertyNamesChecker*/ null,
                                        /*collectionValidator*/ null,
                                        nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default,
                                        /*isTopLevelPropertyValue*/ false,
                                        /*insideComplexValue*/ false,
                                        propertyName,
                                        edmProperty == null);

                                    if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null)
                                    {
                                        duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property);
                                        property.Value = propertyValue;
                                        var propertyAnnotations = duplicatePropertyNamesChecker.GetCustomPropertyAnnotations(propertyName);
                                        if (propertyAnnotations != null)
                                        {
                                            foreach (var annotation in propertyAnnotations)
                                            {
                                                if (annotation.Value != null)
                                                {
                                                    // annotation.Value == null indicates that this annotation should be skipped.
                                                    property.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Key, annotation.Value.ToODataValue()));
                                                }
                                            }
                                        }

                                        properties.Add(property);
                                    }
                                }

                                break;

                            case PropertyParsingResult.EndOfObject:
                                break;

                            case PropertyParsingResult.MetadataReferenceProperty:
                                throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedMetadataReferenceProperty(propertyName));
                        }
                    });
            }

            Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected.");
            this.JsonReader.ReadEndObject();

            complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties);

            this.DecreaseRecursionDepth();

            return complexValue;
        }
 protected override void ProcessComplexTypeReference(IEdmComplexTypeReference element)
 {
     this.CheckSchemaElementReference(element.ComplexDefinition());
 }
 protected override void ProcessComplexTypeReference(IEdmComplexTypeReference element)
 {
     this.CheckSchemaElementReference(element.ComplexDefinition());
 }
コード例 #28
0
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="propertyTypeReference">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param>
        /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param>
        /// <param name="collectionValidator">The collection validator instance to validate the type names and type kinds of collection items; null if no validation is needed.</param>
        /// <remarks>The current recursion depth should be a value, measured by the number of complex and collection values between
        /// this complex value and the top-level payload, not including this one.</remarks>
        internal void WriteComplexValue(
            ODataComplexValue complexValue,
            IEdmTypeReference propertyTypeReference,
            bool isOpenPropertyType,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            this.IncreaseRecursionDepth();

            // Start the object scope which will represent the entire complex instance
            this.JsonWriter.StartObjectScope();

            // Write the "__metadata" : { "type": "typename" }
            // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely
            string typeName = complexValue.TypeName;

            if (collectionValidator != null)
            {
                collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex);
            }

            // resolve the type name to the type; if no type name is specified we will use the
            // type inferred from metadata
            IEdmComplexTypeReference complexValueTypeReference =
                WriterValidationUtils.ResolveTypeNameForWriting(this.Model, propertyTypeReference, 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;
            }

            if (typeName != null)
            {
                // Write the __metadata object
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataName);
                this.JsonWriter.StartObjectScope();

                // "type": "typename"
                this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                this.JsonWriter.WriteValue(typeName);

                // End the __metadata
                this.JsonWriter.EndObjectScope();
            }

            // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties.
            this.WriteProperties(
                complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(),
                complexValue.Properties,
                true /* isComplexValue */,
                duplicatePropertyNamesChecker,
                null /*projectedProperties */);

            // End the object scope which represents the complex instance
            this.JsonWriter.EndObjectScope();

            this.DecreaseRecursionDepth();
        }
コード例 #29
0
ファイル: EdmComplexObject.cs プロジェクト: joshcomley/WebApi
		/// <summary>
		/// Initializes a new instance of the <see cref="EdmStructuredObject"/> class.
		/// </summary>
		/// <param name="edmType">The <see cref="IEdmComplexTypeReference"/> of this object.</param>
		/// <param name="assembliesResolver">The assemblies resolve to use for type resolution</param>
		public EdmComplexObject(IEdmComplexTypeReference edmType, AssembliesResolver assembliesResolver)
            : this(edmType.ComplexDefinition(), assembliesResolver, edmType.IsNullable)
        {
        }