/// <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)); } }
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)); } }