/// <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 ODataResource 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(writeContext.Context, propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataEdmTypeSerializer).Name);
                }

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

            string typeName = complexType.FullName();

            var value = new ODataResource
            {
                Properties = propertyCollection,
                TypeName   = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return(value);
        }
        /// <summary>
        /// Creates the <see cref="ODataProperty"/> to be written for the given entity and the structural property.
        /// </summary>
        /// <param name="structuralProperty">The EDM structural property being written.</param>
        /// <param name="resourceContext">The context for the entity instance being written.</param>
        /// <returns>The <see cref="ODataProperty"/> to write.</returns>
        public virtual ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, ResourceContext resourceContext)
        {
            if (structuralProperty == null)
            {
                throw Error.ArgumentNull("structuralProperty");
            }
            if (resourceContext == null)
            {
                throw Error.ArgumentNull("resourceContext");
            }

            ODataSerializerContext writeContext = resourceContext.SerializerContext;

            ODataEdmTypeSerializer serializer = SerializerProvider.GetEdmTypeSerializer(resourceContext.Context, structuralProperty.Type);

            if (serializer == null)
            {
                throw new SerializationException(
                          Error.Format(SRResources.TypeCannotBeSerialized, structuralProperty.Type.FullName(), typeof(ODataOutputFormatter).Name));
            }

            object propertyValue = resourceContext.GetPropertyValue(structuralProperty.Name);

            IEdmTypeReference propertyType = structuralProperty.Type;

            if (propertyValue != null)
            {
                if (!propertyType.IsPrimitive() && !propertyType.IsEnum())
                {
                    IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType());
                    if (propertyType != null && propertyType != actualType)
                    {
                        propertyType = actualType;
                    }
                }
            }

            return(serializer.CreateProperty(propertyValue, propertyType, structuralProperty.Name, writeContext));
        }
Exemple #3
0
        /// <summary>
        /// Creates the <see cref="ODataProperty"/> to be written for the given entity and the structural property.
        /// </summary>
        /// <param name="structuralProperty">The EDM structural property being written.</param>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <returns>The <see cref="ODataProperty"/> to write.</returns>
        public virtual async Task <ODataProperty> CreateStructuralPropertyAsync(IEdmStructuralProperty structuralProperty, EntityInstanceContext entityInstanceContext)
        {
            if (structuralProperty == null)
            {
                throw Error.ArgumentNull("structuralProperty");
            }
            if (entityInstanceContext == null)
            {
                throw Error.ArgumentNull("entityInstanceContext");
            }

            ODataSerializerContext writeContext = entityInstanceContext.SerializerContext;

            ODataEdmTypeSerializer serializer = SerializerProvider.GetEdmTypeSerializer(structuralProperty.Type);

            if (serializer == null)
            {
                throw new SerializationException(
                          Error.Format(SRResources.TypeCannotBeSerialized, structuralProperty.Type.FullName(), typeof(ODataOutputFormatter).Name));
            }

            object propertyValue = entityInstanceContext.GetPropertyValue(structuralProperty.Name);

            IEdmTypeReference propertyType = structuralProperty.Type;

            if (propertyValue != null)
            {
                IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType());
                if (propertyType != null && propertyType != actualType)
                {
                    propertyType = actualType;
                }
            }

            return(await serializer.CreateProperty(propertyValue, propertyType, structuralProperty.Name, writeContext, entityInstanceContext));
        }
        internal async Task <List <ODataProperty> > AppendDynamicProperties(object source, IEdmStructuredTypeReference structuredType,
                                                                            ODataSerializerContext writeContext, List <ODataProperty> declaredProperties,
                                                                            string[] selectedDynamicProperties)
        {
            Contract.Assert(source != null);
            Contract.Assert(structuredType != null);
            Contract.Assert(writeContext != null);
            Contract.Assert(writeContext.Model != null);

            PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(
                structuredType.StructuredDefinition(), writeContext.Model);

            IEdmStructuredObject structuredObject = source as IEdmStructuredObject;
            object value;
            IDelta delta = source as IDelta;

            if (delta == null)
            {
                if (dynamicPropertyInfo == null || structuredObject == null ||
                    !structuredObject.TryGetPropertyValue(dynamicPropertyInfo.Name, out value) || value == null)
                {
                    return(null);
                }
            }
            else
            {
                value = ((EdmStructuredObject)structuredObject).TryGetDynamicProperties();
            }

            IDictionary <string, object> dynamicPropertyDictionary = (IDictionary <string, object>)value;

            // Build a HashSet to store the declared property names.
            // It is used to make sure the dynamic property name is different from all declared property names.
            HashSet <string>     declaredPropertyNameSet = new HashSet <string>(declaredProperties.Select(p => p.Name));
            List <ODataProperty> dynamicProperties       = new List <ODataProperty>();
            IEnumerable <KeyValuePair <string, object> > dynamicPropertiesToSelect =
                dynamicPropertyDictionary.Where(
                    x => !selectedDynamicProperties.Any() || selectedDynamicProperties.Contains(x.Key));

            foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertiesToSelect)
            {
                if (String.IsNullOrEmpty(dynamicProperty.Key) || dynamicProperty.Value == null)
                {
                    continue;                     // skip the null object
                }

                if (declaredPropertyNameSet.Contains(dynamicProperty.Key))
                {
                    throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName,
                                                 dynamicProperty.Key, structuredType.FullName());
                }

                IEdmTypeReference edmTypeReference = writeContext.GetEdmType(dynamicProperty.Value,
                                                                             dynamicProperty.Value.GetType());
                if (edmTypeReference == null)
                {
                    throw Error.NotSupported(SRResources.TypeOfDynamicPropertyNotSupported,
                                             dynamicProperty.Value.GetType().FullName, dynamicProperty.Key);
                }

                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.DynamicPropertyCannotBeSerialized, dynamicProperty.Key,
                                             edmTypeReference.FullName());
                }

                dynamicProperties.Add(await propertySerializer.CreateProperty(
                                          dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext, source, structuredType, null, null));
            }

            return(dynamicProperties);
        }
        /// <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 async Task <ODataComplexValue> CreateODataComplexValueAsync(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(
                        await 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 =
                    await 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 virtual void AppendDynamicProperties(ODataResource resource, SelectExpandNode selectExpandNode,
                                                    ResourceContext resourceContext)
        {
            Contract.Assert(resource != null);
            Contract.Assert(selectExpandNode != null);
            Contract.Assert(resourceContext != null);

            if (!resourceContext.StructuredType.IsOpen || // non-open type
                (!selectExpandNode.SelectAllDynamicProperties && !selectExpandNode.SelectedDynamicProperties.Any()))
            {
                return;
            }

            bool nullDynamicPropertyEnabled = false;

            if (resourceContext.Request != null)
            {
                // TODO:

                /*
                 * HttpConfiguration configuration = resourceContext.Request.GetConfiguration();
                 * if (configuration != null)
                 * {
                 *  nullDynamicPropertyEnabled = configuration.HasEnabledNullDynamicProperty();
                 * }*/
            }

            IEdmStructuredType   structuredType   = resourceContext.StructuredType;
            IEdmStructuredObject structuredObject = resourceContext.EdmObject;
            object value;
            IDelta delta = structuredObject as IDelta;

            if (delta == null)
            {
                PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(structuredType,
                                                                                              resourceContext.EdmModel);
                if (dynamicPropertyInfo == null || structuredObject == null ||
                    !structuredObject.TryGetPropertyValue(dynamicPropertyInfo.Name, out value) || value == null)
                {
                    return;
                }
            }
            else
            {
                value = ((EdmStructuredObject)structuredObject).TryGetDynamicProperties();
            }

            IDictionary <string, object> dynamicPropertyDictionary = (IDictionary <string, object>)value;

            // Build a HashSet to store the declared property names.
            // It is used to make sure the dynamic property name is different from all declared property names.
            HashSet <string>     declaredPropertyNameSet = new HashSet <string>(resource.Properties.Select(p => p.Name));
            List <ODataProperty> dynamicProperties       = new List <ODataProperty>();
            IEnumerable <KeyValuePair <string, object> > dynamicPropertiesToSelect =
                dynamicPropertyDictionary.Where(
                    x =>
                    !selectExpandNode.SelectedDynamicProperties.Any() ||
                    selectExpandNode.SelectedDynamicProperties.Contains(x.Key));

            foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertiesToSelect)
            {
                if (String.IsNullOrEmpty(dynamicProperty.Key))
                {
                    continue;
                }

                if (dynamicProperty.Value == null)
                {
                    if (nullDynamicPropertyEnabled)
                    {
                        dynamicProperties.Add(new ODataProperty
                        {
                            Name  = dynamicProperty.Key,
                            Value = new ODataNullValue()
                        });
                    }

                    continue;
                }

                if (declaredPropertyNameSet.Contains(dynamicProperty.Key))
                {
                    throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName,
                                                 dynamicProperty.Key, structuredType.FullTypeName());
                }

                IEdmTypeReference edmTypeReference = resourceContext.SerializerContext.GetEdmType(dynamicProperty.Value,
                                                                                                  dynamicProperty.Value.GetType());
                if (edmTypeReference == null)
                {
                    throw Error.NotSupported(SRResources.TypeOfDynamicPropertyNotSupported,
                                             dynamicProperty.Value.GetType().FullName, dynamicProperty.Key);
                }

                if (edmTypeReference.IsStructured() ||
                    (edmTypeReference.IsCollection() && edmTypeReference.AsCollection().ElementType().IsStructured()))
                {
                    if (resourceContext.DynamicComplexProperties == null)
                    {
                        resourceContext.DynamicComplexProperties = new ConcurrentDictionary <string, object>();
                    }

                    resourceContext.DynamicComplexProperties.Add(dynamicProperty);
                }
                else
                {
                    ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(resourceContext.Context, edmTypeReference);
                    if (propertySerializer == null)
                    {
                        throw Error.NotSupported(SRResources.DynamicPropertyCannotBeSerialized, dynamicProperty.Key,
                                                 edmTypeReference.FullName());
                    }

                    dynamicProperties.Add(propertySerializer.CreateProperty(
                                              dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, resourceContext.SerializerContext));
                }
            }

            if (dynamicProperties.Any())
            {
                resource.Properties = resource.Properties.Concat(dynamicProperties);
            }
        }