示例#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);
        }
        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);
            }
        }
示例#3
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>
        /// 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);
        }
        internal static object CreateResource(IEdmComplexTypeReference edmComplexType, ODataDeserializerContext readContext)
        {
            Contract.Assert(edmComplexType != null);

            if (readContext.IsUntyped)
            {
                return new EdmComplexObject(edmComplexType);
            }
            else
            {
                Type clrType = EdmLibHelpers.GetClrType(edmComplexType, readContext.Model);
                if (clrType == null)
                {
                    throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, edmComplexType.FullName());
                }

                return Activator.CreateInstance(clrType);
            }
        }
        /// <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;
            }
        }
        /// <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;
        }
        internal static object CreateResource(IEdmComplexTypeReference complexType, ODataDeserializerContext readContext)
        {
            if (complexType == null)
            {
                throw Error.ArgumentNull("complexType");
            }
            if (readContext == null)
            {
                throw Error.ArgumentNull("readContext");
            }

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

            if (readContext.IsUntyped)
            {
                return new EdmComplexObject(complexType);
            }
            else
            {
                Type clrType = EdmLibHelpers.GetClrType(complexType, readContext.Model);
                if (clrType == null)
                {
                    throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, complexType.FullName());
                }

                if (readContext.IsDeltaOfT)
                {
                    Type elementType = readContext.ResourceType.GetGenericArguments()[0];
                    if (elementType != clrType)
                    {
                        // Just create the object for inline complex type
                        return Activator.CreateInstance(clrType);
                    }

                    IEnumerable<string> structuralProperties = complexType.StructuralProperties()
                        .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model));

                    if (complexType.IsOpen())
                    {
                        PropertyInfo dynamicDictionaryPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(
                            complexType.StructuredDefinition(), model);

                        return Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties,
                            dynamicDictionaryPropertyInfo);
                    }
                    else
                    {
                        return Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties);
                    }
                }
                else
                {
                    return Activator.CreateInstance(clrType);
                }
            }
        }
示例#9
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);
            }
        }
示例#10
0
        internal static object CreateResource(IEdmComplexTypeReference edmComplexType, ODataDeserializerContext readContext)
        {
            Contract.Assert(edmComplexType != null);

            if (readContext.IsUntyped)
            {
                return(new EdmComplexObject(edmComplexType));
            }
            else
            {
                Type clrType = EdmLibHelpers.GetClrType(edmComplexType, readContext.Model);
                if (clrType == null)
                {
                    throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, edmComplexType.FullName());
                }

                return(Activator.CreateInstance(clrType));
            }
        }
        /// <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;
        }
        /// <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;
        }
        /// <summary>
        /// Reads a complex value.
        /// </summary>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object 
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="insideComplexValue">true if we are reading a complex value and the reader is already positioned inside the complex value; otherwise false.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <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(
            bool insideJsonObjectValue,
            bool insideComplexValue,
            string propertyName,
            IEdmComplexTypeReference complexValueTypeReference,
            string payloadTypeName,
            SerializationTypeNameAnnotation serializationTypeNameAnnotation,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            if (!insideJsonObjectValue && !insideComplexValue)
            {
                if (this.JsonReader.NodeType != JsonNodeType.StartObject)
                {
                    string typeName = complexValueTypeReference != null ? complexValueTypeReference.FullName() : payloadTypeName;
                    throw new ODataException(
                        string.Format(CultureInfo.InvariantCulture,
                        "The property with name '{0}' was found with a value node of type '{1}'; however, a complex value of type '{2}' was expected.",
                        propertyName, this.JsonReader.NodeType, typeName));
                }

                this.JsonReader.Read();
            }

            return this.ReadComplexValue(complexValueTypeReference, payloadTypeName, serializationTypeNameAnnotation, duplicatePropertyNamesChecker);
        }
        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));
                    }
                }
            }
        }
示例#15
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);
        }
示例#16
0
        internal static object CreateResource(IEdmComplexTypeReference complexType, ODataDeserializerContext readContext)
        {
            if (complexType == null)
            {
                throw Error.ArgumentNull("complexType");
            }
            if (readContext == null)
            {
                throw Error.ArgumentNull("readContext");
            }

            IEdmModel model = readContext.Model;

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

            if (readContext.IsUntyped)
            {
                return(new EdmComplexObject(complexType));
            }
            else
            {
                Type clrType = EdmLibHelpers.GetClrType(complexType, readContext.Model);
                if (clrType == null)
                {
                    throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, complexType.FullName());
                }

                if (readContext.IsDeltaOfT)
                {
                    Type elementType = readContext.ResourceType.GetGenericArguments()[0];
                    if (elementType != clrType)
                    {
                        // Just create the object for inline complex type
                        return(Activator.CreateInstance(clrType));
                    }

                    IEnumerable <string> structuralProperties = complexType.StructuralProperties()
                                                                .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model));

                    if (complexType.IsOpen())
                    {
                        PropertyInfo dynamicDictionaryPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(
                            complexType.StructuredDefinition(), model);

                        return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties,
                                                        dynamicDictionaryPropertyInfo));
                    }
                    else
                    {
                        return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties));
                    }
                }
                else
                {
                    return(Activator.CreateInstance(clrType));
                }
            }
        }