/// <summary>
        /// Populates the metadata for the properties of the given resource type
        /// </summary>
        /// <param name="parentResourceType">resource type whose properties metadata needs to be populated</param>
        /// <param name="knownTypes">list of known types</param>
        /// <param name="childTypes">list of already known types and their immediate children</param>
        /// <param name="unvisitedTypes">list of unvisited type</param>
        /// <param name="entitySets">Available entity sets.</param>
        private static void BuildTypeProperties(
            ResourceType parentResourceType, 
            IDictionary<Type, ResourceType> knownTypes, 
            IDictionary<ResourceType, List<ResourceType>> childTypes,
            Queue<ResourceType> unvisitedTypes, 
            IEnumerable<ResourceSet> entitySets)
        {
            Debug.Assert(parentResourceType != null, "parentResourceType != null");
            Debug.Assert(knownTypes != null, "knownTypes != null");
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null");

            BindingFlags bindingFlags = WebUtil.PublicInstanceBindingFlags;

            // For non root types, we should only look for properties that are declared for this type
            if (parentResourceType.BaseType != null)
            {
                bindingFlags = bindingFlags | BindingFlags.DeclaredOnly;
            }

            HashSet<string> propertiesToBeIgnored = new HashSet<string>(IgnorePropertiesAttribute.GetProperties(parentResourceType.InstanceType, false /*inherit*/, bindingFlags), StringComparer.Ordinal);
            Debug.Assert(parentResourceType.IsOpenType == false, "ReflectionServiceProvider does not support Open types.");

            HashSet<string> etagPropertyNames = new HashSet<string>(LoadETagProperties(parentResourceType), StringComparer.Ordinal);

            ResourceKeyKind keyKind = (ResourceKeyKind)Int32.MaxValue;
            PropertyInfo[] properties = parentResourceType.InstanceType.GetProperties(bindingFlags);
            foreach (PropertyInfo property in properties)
            {
                // Ignore the properties which are specified in the IgnoreProperties attribute
                if (propertiesToBeIgnored.Contains(property.Name))
                {
                    continue;
                }

                if (property.CanRead && property.GetIndexParameters().Length == 0)
                {
                    ResourcePropertyKind kind = (ResourcePropertyKind)(-1);
                    ResourceKeyKind currentKeyKind = (ResourceKeyKind)(-1);
                    ResourceType resourceType;
                    Type resourcePropertyType = property.PropertyType;
                    ResourceSet container = null;
                    bool collection = false;

                    if (!TryGetType(knownTypes, resourcePropertyType, out resourceType))
                    {
                        Type collectionType = GetIEnumerableElement(property.PropertyType);
                        if (collectionType != null)
                        {
                            TryGetType(knownTypes, collectionType, out resourceType);

                            // Even if the above method returns false, we should set the
                            // following variable appropriately, so that we can use them below
                            collection = true;
                            resourcePropertyType = collectionType;
                        }
                    }

                    if (resourceType != null)
                    {
                        #region Already Known Type
                        if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                        {
                            // Check for key property only on root types, since keys must be defined on the root types
                            if (parentResourceType.BaseType == null && parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType && IsPropertyKeyProperty(property, out currentKeyKind))
                            {
                                if ((int)currentKeyKind < (int)keyKind)
                                {
                                    if (parentResourceType.KeyProperties.Count != 0)
                                    {
                                        // Remove the existing property as key property - mark it as non key property
                                        parentResourceType.RemoveKeyProperties();
                                    }

                                    keyKind = currentKeyKind;
                                    kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                }
                                else if ((int)currentKeyKind == (int)keyKind)
                                {
                                    Debug.Assert(currentKeyKind == ResourceKeyKind.AttributedKey, "This is the only way of specifying composite keys");
                                    kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                }
                                else
                                {
                                    kind = ResourcePropertyKind.Primitive;
                                }
                            }
                            else
                            {
                                kind = ResourcePropertyKind.Primitive;
                            }
                        }
                        else if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            kind = ResourcePropertyKind.ComplexType;
                        }
                        else if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                        {
                            kind = collection ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                        }
                        #endregion // Already Known Type
                    }
                    else
                    {
                        resourceType = IsEntityOrComplexType(resourcePropertyType, knownTypes, childTypes, unvisitedTypes);
                        if (resourceType != null)
                        {
                            if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                            {
                                kind = ResourcePropertyKind.ComplexType;
                            }
                            else
                            {
                                Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Must be an entity type");
                                kind = collection ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                            }
                        }
                    }

                    // if resource type is null OR
                    // if resource type is a collection of primitive or complex types OR
                    // if complex type has a property of entity type
                    if (resourceType == null ||
                        (resourceType.ResourceTypeKind != ResourceTypeKind.EntityType && collection) ||
                        (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType && parentResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType))
                    {
                        if (resourceType == null)
                        {
                            if (CommonUtil.IsUnsupportedType(resourcePropertyType))
                            {
                                throw new InvalidOperationException(Strings.BadProvider_UnsupportedPropertyType(property.Name, parentResourceType.FullName));
                            }

                            throw new InvalidOperationException(Strings.ReflectionProvider_InvalidProperty(property.Name, parentResourceType.FullName));
                        }
                        else
                        {
                            // collection of complex types not supported
                            throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfPrimitiveOrComplexNotSupported(property.Name, parentResourceType.FullName));
                        }
                    }

                    if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                    {
                        container = InternalGetContainerForResourceType(resourcePropertyType, entitySets);
                        if (container == null)
                        {
                            throw new InvalidOperationException(Strings.ReflectionProvider_EntityPropertyWithNoEntitySet(parentResourceType.FullName, property.Name));
                        }
                    }

                    if (etagPropertyNames.Remove(property.Name))
                    {
                        kind |= ResourcePropertyKind.ETag;
                    }

                    ResourceProperty resourceProperty = new ResourceProperty(property.Name, kind, resourceType);
                    MimeTypeAttribute attribute = MimeTypeAttribute.GetMimeTypeAttribute(property);
                    if (attribute != null)
                    {
                        resourceProperty.MimeType = attribute.MimeType;
                    }

                    parentResourceType.AddProperty(resourceProperty);
                }
                else
                {
                    throw new InvalidOperationException(Strings.ReflectionProvider_InvalidProperty(property.Name, parentResourceType.FullName));
                }
            }

            if (parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType &&
                (parentResourceType.KeyProperties == null || parentResourceType.KeyProperties.Count == 0))
            {
                throw new InvalidOperationException(Strings.ReflectionProvider_KeyPropertiesCannotBeIgnored(parentResourceType.FullName));
            }

            if (etagPropertyNames.Count != 0)
            {
                throw new InvalidOperationException(Strings.ReflectionProvider_ETagPropertyNameNotValid(etagPropertyNames.ElementAt(0), parentResourceType.FullName));
            }
        }
Example #2
0
        private static void BuildTypeProperties(ResourceType parentResourceType, IDictionary <Type, ResourceType> knownTypes, IDictionary <ResourceType, List <ResourceType> > childTypes, Queue <ResourceType> unvisitedTypes, IEnumerable <ResourceSet> entitySets)
        {
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;

            if (parentResourceType.BaseType != null)
            {
                bindingFlags |= BindingFlags.DeclaredOnly;
            }
            HashSet <string> set    = new HashSet <string>(IgnorePropertiesAttribute.GetProperties(parentResourceType.InstanceType, false, bindingFlags), StringComparer.Ordinal);
            HashSet <string> source = new HashSet <string>(LoadETagProperties(parentResourceType), StringComparer.Ordinal);
            ResourceKeyKind  kind   = (ResourceKeyKind)0x7fffffff;

            PropertyInfo[] properties = parentResourceType.InstanceType.GetProperties(bindingFlags);
            if (!properties.Any <PropertyInfo>() && (parentResourceType.BaseType == null))
            {
                throw new NotSupportedException(System.Data.Services.Strings.ReflectionProvider_ResourceTypeHasNoPublicallyVisibleProperties(parentResourceType.FullName));
            }
            foreach (PropertyInfo info in properties)
            {
                if (!set.Contains(info.Name))
                {
                    ResourceType collectionResourceType;
                    if (!info.CanRead || (info.GetIndexParameters().Length != 0))
                    {
                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_InvalidProperty(info.Name, parentResourceType.FullName));
                    }
                    ResourcePropertyKind collection = (ResourcePropertyKind)(-1);
                    Type propertyType = info.PropertyType;
                    bool flag         = false;
                    if (!BaseServiceProvider.TryGetType(knownTypes, propertyType, out collectionResourceType))
                    {
                        Type iEnumerableElement = BaseServiceProvider.GetIEnumerableElement(info.PropertyType);
                        if (iEnumerableElement != null)
                        {
                            BaseServiceProvider.TryGetType(knownTypes, iEnumerableElement, out collectionResourceType);
                            flag         = true;
                            propertyType = iEnumerableElement;
                        }
                    }
                    if (collectionResourceType != null)
                    {
                        if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                        {
                            if (flag)
                            {
                                collection = ResourcePropertyKind.Collection;
                            }
                            else
                            {
                                ResourceKeyKind kind3;
                                if (((parentResourceType.BaseType == null) && (parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType)) && IsPropertyKeyProperty(info, out kind3))
                                {
                                    if (kind3 < kind)
                                    {
                                        if (parentResourceType.KeyProperties.Count != 0)
                                        {
                                            parentResourceType.RemoveKeyProperties();
                                        }
                                        kind       = kind3;
                                        collection = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else if (kind3 == kind)
                                    {
                                        collection = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else
                                    {
                                        collection = ResourcePropertyKind.Primitive;
                                    }
                                }
                                else
                                {
                                    collection = ResourcePropertyKind.Primitive;
                                }
                            }
                        }
                        else if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            collection = flag ? ResourcePropertyKind.Collection : ResourcePropertyKind.ComplexType;
                        }
                        else if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                        {
                            collection = flag ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                        }
                    }
                    else
                    {
                        collectionResourceType = IsEntityOrComplexType(propertyType, knownTypes, childTypes, unvisitedTypes);
                        if (collectionResourceType != null)
                        {
                            if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                            {
                                if (flag)
                                {
                                    if (BaseServiceProvider.GetIEnumerableElement(propertyType) != null)
                                    {
                                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_CollectionOfCollectionProperty(info.Name, parentResourceType.FullName));
                                    }
                                    collection = ResourcePropertyKind.Collection;
                                }
                                else
                                {
                                    collection = ResourcePropertyKind.ComplexType;
                                }
                            }
                            else
                            {
                                collection = flag ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                            }
                        }
                    }
                    if ((collectionResourceType == null) || ((collectionResourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && (parentResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)))
                    {
                        if (collectionResourceType != null)
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_ComplexTypeWithNavigationProperty(info.Name, parentResourceType.FullName));
                        }
                        if (flag && (BaseServiceProvider.GetIEnumerableElement(propertyType) != null))
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_CollectionOfCollectionProperty(info.Name, parentResourceType.FullName));
                        }
                        if (flag)
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_CollectionOfUnsupportedTypeProperty(info.Name, parentResourceType.FullName, propertyType));
                        }
                        if (CommonUtil.IsUnsupportedType(propertyType))
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.BadProvider_UnsupportedPropertyType(info.Name, parentResourceType.FullName));
                        }
                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_InvalidProperty(info.Name, parentResourceType.FullName));
                    }
                    if ((collectionResourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && (InternalGetContainerForResourceType(propertyType, entitySets) == null))
                    {
                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_EntityPropertyWithNoEntitySet(parentResourceType.FullName, info.Name));
                    }
                    if (collection == ResourcePropertyKind.Collection)
                    {
                        collectionResourceType = ResourceType.GetCollectionResourceType(collectionResourceType);
                    }
                    if (source.Remove(info.Name))
                    {
                        collection |= ResourcePropertyKind.ETag;
                    }
                    ResourceProperty  property          = new ResourceProperty(info.Name, collection, collectionResourceType);
                    MimeTypeAttribute mimeTypeAttribute = MimeTypeAttribute.GetMimeTypeAttribute(info);
                    if (mimeTypeAttribute != null)
                    {
                        property.MimeType = mimeTypeAttribute.MimeType;
                    }
                    parentResourceType.AddProperty(property);
                }
            }
            if ((parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && ((parentResourceType.KeyProperties == null) || (parentResourceType.KeyProperties.Count == 0)))
            {
                throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_KeyPropertiesCannotBeIgnored(parentResourceType.FullName));
            }
            if (source.Count != 0)
            {
                throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_ETagPropertyNameNotValid(source.ElementAt <string>(0), parentResourceType.FullName));
            }
        }
        private static void BuildTypeProperties(ResourceType parentResourceType, IDictionary<Type, ResourceType> knownTypes, IDictionary<ResourceType, List<ResourceType>> childTypes, Queue<ResourceType> unvisitedTypes, IEnumerable<ResourceSet> entitySets)
        {
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
            if (parentResourceType.BaseType != null)
            {
                bindingFlags |= BindingFlags.DeclaredOnly;
            }
            HashSet<string> set = new HashSet<string>(IgnorePropertiesAttribute.GetProperties(parentResourceType.InstanceType, false, bindingFlags), StringComparer.Ordinal);
            HashSet<string> source = new HashSet<string>(LoadETagProperties(parentResourceType), StringComparer.Ordinal);
            ResourceKeyKind kind = (ResourceKeyKind) 0x7fffffff;
            PropertyInfo[] properties = parentResourceType.InstanceType.GetProperties(bindingFlags);
            if (!properties.Any<PropertyInfo>() && (parentResourceType.BaseType == null))
            {
                throw new NotSupportedException(System.Data.Services.Strings.ReflectionProvider_ResourceTypeHasNoPublicallyVisibleProperties(parentResourceType.FullName));
            }
            foreach (PropertyInfo info in properties)
            {
                if (!set.Contains(info.Name))
                {
                    ResourceType collectionResourceType;
                    if (!info.CanRead || (info.GetIndexParameters().Length != 0))
                    {
                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_InvalidProperty(info.Name, parentResourceType.FullName));
                    }
					ResourcePropertyKind collection = (ResourcePropertyKind)(-1);
                    Type propertyType = info.PropertyType;
                    bool flag = false;
                    if (!BaseServiceProvider.TryGetType(knownTypes, propertyType, out collectionResourceType))
                    {
                        Type iEnumerableElement = BaseServiceProvider.GetIEnumerableElement(info.PropertyType);
                        if (iEnumerableElement != null)
                        {
                            BaseServiceProvider.TryGetType(knownTypes, iEnumerableElement, out collectionResourceType);
                            flag = true;
                            propertyType = iEnumerableElement;
                        }
                    }
                    if (collectionResourceType != null)
                    {
                        if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                        {
                            if (flag)
                            {
                                collection = ResourcePropertyKind.Collection;
                            }
                            else
                            {
                                ResourceKeyKind kind3;
                                if (((parentResourceType.BaseType == null) && (parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType)) && IsPropertyKeyProperty(info, out kind3))
                                {
                                    if (kind3 < kind)
                                    {
                                        if (parentResourceType.KeyProperties.Count != 0)
                                        {
                                            parentResourceType.RemoveKeyProperties();
                                        }
                                        kind = kind3;
                                        collection = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else if (kind3 == kind)
                                    {
                                        collection = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else
                                    {
                                        collection = ResourcePropertyKind.Primitive;
                                    }
                                }
                                else
                                {
                                    collection = ResourcePropertyKind.Primitive;
                                }
                            }
                        }
                        else if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            collection = flag ? ResourcePropertyKind.Collection : ResourcePropertyKind.ComplexType;
                        }
                        else if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                        {
                            collection = flag ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                        }
                    }
                    else
                    {
                        collectionResourceType = IsEntityOrComplexType(propertyType, knownTypes, childTypes, unvisitedTypes);
                        if (collectionResourceType != null)
                        {
                            if (collectionResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                            {
                                if (flag)
                                {
                                    if (BaseServiceProvider.GetIEnumerableElement(propertyType) != null)
                                    {
                                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_CollectionOfCollectionProperty(info.Name, parentResourceType.FullName));
                                    }
                                    collection = ResourcePropertyKind.Collection;
                                }
                                else
                                {
                                    collection = ResourcePropertyKind.ComplexType;
                                }
                            }
                            else
                            {
                                collection = flag ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                            }
                        }
                    }
                    if ((collectionResourceType == null) || ((collectionResourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && (parentResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)))
                    {
                        if (collectionResourceType != null)
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_ComplexTypeWithNavigationProperty(info.Name, parentResourceType.FullName));
                        }
                        if (flag && (BaseServiceProvider.GetIEnumerableElement(propertyType) != null))
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_CollectionOfCollectionProperty(info.Name, parentResourceType.FullName));
                        }
                        if (flag)
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_CollectionOfUnsupportedTypeProperty(info.Name, parentResourceType.FullName, propertyType));
                        }
                        if (CommonUtil.IsUnsupportedType(propertyType))
                        {
                            throw new InvalidOperationException(System.Data.Services.Strings.BadProvider_UnsupportedPropertyType(info.Name, parentResourceType.FullName));
                        }
                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_InvalidProperty(info.Name, parentResourceType.FullName));
                    }
                    if ((collectionResourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && (InternalGetContainerForResourceType(propertyType, entitySets) == null))
                    {
                        throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_EntityPropertyWithNoEntitySet(parentResourceType.FullName, info.Name));
                    }
                    if (collection == ResourcePropertyKind.Collection)
                    {
                        collectionResourceType = ResourceType.GetCollectionResourceType(collectionResourceType);
                    }
                    if (source.Remove(info.Name))
                    {
                        collection |= ResourcePropertyKind.ETag;
                    }
                    ResourceProperty property = new ResourceProperty(info.Name, collection, collectionResourceType);
                    MimeTypeAttribute mimeTypeAttribute = MimeTypeAttribute.GetMimeTypeAttribute(info);
                    if (mimeTypeAttribute != null)
                    {
                        property.MimeType = mimeTypeAttribute.MimeType;
                    }
                    parentResourceType.AddProperty(property);
                }
            }
            if ((parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType) && ((parentResourceType.KeyProperties == null) || (parentResourceType.KeyProperties.Count == 0)))
            {
                throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_KeyPropertiesCannotBeIgnored(parentResourceType.FullName));
            }
            if (source.Count != 0)
            {
                throw new InvalidOperationException(System.Data.Services.Strings.ReflectionProvider_ETagPropertyNameNotValid(source.ElementAt<string>(0), parentResourceType.FullName));
            }
        }