Beispiel #1
0
        /// <summary>
        /// Generates a string to be used as the skip token value within the next link.
        /// </summary>
        /// <param name="lastMember"> Object based on which SkipToken value will be generated.</param>
        /// <param name="model">The edm model.</param>
        /// <param name="orderByNodes">List of orderByNodes used to generate the skiptoken value.</param>
        /// <returns>Value for the skiptoken to be used in the next link.</returns>
        private static string GenerateSkipTokenValue(Object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes)
        {
            if (lastMember == null)
            {
                return(String.Empty);
            }

            IEnumerable <IEdmProperty> propertiesForSkipToken = GetPropertiesForSkipToken(lastMember, model, orderByNodes);
            StringBuilder skipTokenBuilder = new StringBuilder(String.Empty);

            if (propertiesForSkipToken == null)
            {
                return(skipTokenBuilder.ToString());
            }

            int    count = 0;
            string uriLiteral;
            object value;
            int    lastIndex         = propertiesForSkipToken.Count() - 1;
            IEdmStructuredObject obj = lastMember as IEdmStructuredObject;

            foreach (IEdmProperty edmProperty in propertiesForSkipToken)
            {
                bool   islast          = count == lastIndex;
                string clrPropertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, model);
                if (obj != null)
                {
                    obj.TryGetPropertyValue(clrPropertyName, out value);
                }
                else
                {
                    value = lastMember.GetType().GetProperty(clrPropertyName).GetValue(lastMember);
                }

                if (value == null)
                {
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401);
                }
                else if (edmProperty.Type.IsEnum())
                {
                    ODataEnumValue enumValue = new ODataEnumValue(value.ToString(), value.GetType().FullName);
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(enumValue, ODataVersion.V401, model);
                }
                else if (edmProperty.Type.IsDateTimeOffset() && value is DateTime)
                {
                    var dateTime            = (DateTime)value;
                    var dateTimeOffsetValue = TimeZoneInfoHelper.ConvertToDateTimeOffset(dateTime);
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(dateTimeOffsetValue, ODataVersion.V401, model);
                }
                else
                {
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401, model);
                }

                skipTokenBuilder.Append(edmProperty.Name).Append(propertyDelimiter).Append(uriLiteral).Append(islast ? String.Empty : CommaDelimiter.ToString());
                count++;
            }

            return(skipTokenBuilder.ToString());
        }
Beispiel #2
0
        /// <summary>
        ///     Convert EdmStructuredObject to an object with type.
        /// </summary>
        /// <param name="edmStructuredObject">An object with EdmStructuredType.</param>
        /// <param name="type">Desired object type.</param>
        /// <returns>Result object.</returns>
        private static object ConvertEdmStructuredObjectToTypedObject(
            IEdmStructuredObject edmStructuredObject, Type type)
        {
            if (edmStructuredObject == null)
            {
                return(null);
            }

            var obj           = Activator.CreateInstance(type);
            var propertyInfos = type.GetProperties();

            foreach (var propertyInfo in propertyInfos)
            {
                if (!propertyInfo.CanWrite)
                {
                    continue;
                }

                object value = null;
                edmStructuredObject.TryGetPropertyValue(propertyInfo.Name, out value);
                if (value == null)
                {
                    propertyInfo.SetValue(obj, value);
                    continue;
                }

                if (!propertyInfo.PropertyType.IsInstanceOfType(value))
                {
                    var edmObj = value as IEdmStructuredObject;
                    if (edmObj == null)
                    {
                        throw new NotSupportedException(string.Format(
                                                            CultureInfo.InvariantCulture,
                                                            propertyInfo.PropertyType.ToString()));
                    }

                    value = ConvertEdmStructuredObjectToTypedObject(edmObj, propertyInfo.PropertyType);
                }

                propertyInfo.SetValue(obj, value);
            }

            return(obj);
        }
        /// <summary>
        /// Gets the property value and wraps it in a DTO wrapper if necessary.
        /// </summary>
        public static bool TryGetPropertyValue <T>(this IEdmStructuredObject targetObject, string propertyName, out T value)
        {
            object internalValue;

            if (targetObject.TryGetPropertyValue(propertyName, out internalValue))
            {
                // wrap by dto wrapper, if applicable
                object wrappedValue;
                if (PropertyValueWrappingHelper.TryWrapEdmObject(internalValue, out wrappedValue))
                {
                    internalValue = wrappedValue;
                }

                // now cast to desired type
                if (internalValue is T)
                {
                    value = (T)internalValue;
                    return(true);
                }
            }

            value = default(T);
            return(false);
        }
Beispiel #4
0
        internal 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(propertySerializer.CreateProperty(
                                          dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext));
            }

            return(dynamicProperties);
        }
        /// <summary>
        /// Appends the dynamic properties of primitive, enum or the collection of them into the given <see cref="ODataResource"/>.
        /// If the dynamic property is a property of the complex or collection of complex, it will be saved into
        /// the dynamic complex properties dictionary of <paramref name="resourceContext"/> and be written later.
        /// </summary>
        /// <param name="resource">The <see cref="ODataResource"/> describing the resource.</param>
        /// <param name="selectExpandNode">The <see cref="SelectExpandNode"/> describing the response graph.</param>
        /// <param name="resourceContext">The context for the resource instance being written.</param>
        public override void AppendDynamicProperties(ODataResource resource, SelectExpandNode selectExpandNode,
                                                     ResourceContext resourceContext)
        {
            if (!resourceContext.StructuredType.IsOpen || // non-open type
                (!selectExpandNode.SelectAllDynamicProperties && selectExpandNode.SelectedDynamicProperties == null))
            {
                return;
            }

            bool nullDynamicPropertyEnabled = true; // false

            if (resourceContext.EdmObject is EdmDeltaComplexObject || resourceContext.EdmObject is EdmDeltaEntityObject)
            {
                nullDynamicPropertyEnabled = true;
            }

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

            if (delta == null)
            {
                PropertyInfo dynamicPropertyInfo = 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>();

            // To test SelectedDynamicProperties == null is enough to filter the dynamic properties.
            // Because if SelectAllDynamicProperties == true, SelectedDynamicProperties should be null always.
            // So `selectExpandNode.SelectedDynamicProperties == null` covers `SelectAllDynamicProperties == true` scenario.
            // If `selectExpandNode.SelectedDynamicProperties != null`, then we should test whether the property is selected or not using "Contains(...)".
            IEnumerable <KeyValuePair <string, object> > dynamicPropertiesToSelect =
                dynamicPropertyDictionary.Where(x => selectExpandNode.SelectedDynamicProperties == null || selectExpandNode.SelectedDynamicProperties.Contains(x.Key));

            foreach (KeyValuePair <string, object> dynamicProperty in dynamicPropertiesToSelect)
            {
                if (string.IsNullOrWhiteSpace(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))
                //{
                //continue;
                //}

                IEdmTypeReference edmTypeReference = GetEdmType(dynamicProperty.Value,
                                                                dynamicProperty.Value.GetType());
                //for non navigational properties it will be null
                if (edmTypeReference == null)
                {
                    dynamicProperties.Add(new ODataProperty
                    {
                        Name  = dynamicProperty.Key,
                        Value = new ODataUntypedValue
                        {
                            RawValue = JsonConvert.SerializeObject(dynamicProperty.Value, new JsonSerializerSettings
                            {
                                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                                TypeNameHandling      = TypeNameHandling.None
                            }),
                            TypeAnnotation = new ODataTypeAnnotation(typeof(string).Name)
                        },
                    });
                }

                else if (edmTypeReference != null)
                {
                    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(edmTypeReference);
                        if (propertySerializer == null)
                        {
                            throw new InvalidOperationException($"Required serilizer for type {edmTypeReference.FullName()} not found");
                        }

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

            if (dynamicProperties.Any())
            {
                resource.Properties = resource.Properties.Concat(dynamicProperties);
            }
        }
        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);
            }
        }