ReflectionServiceProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataWeb / Server / System / Data / Services / Providers / ReflectionServiceProvider.cs / 2 / ReflectionServiceProvider.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides the interface definition for web data service
//      data sources. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Data.Services.Caching;
    using System.Data.Services.Common;
    using System.Diagnostics;
    using System.Linq; 
    using System.Reflection;
    using System.Xml; 
 
    #endregion Namespaces.
 
    /// 
    /// Provides a reflection-based IDataServiceProvider implementation.
    /// 
    [DebuggerDisplay("ReflectionServiceProvider: {Type}")] 
    internal class ReflectionServiceProvider : BaseServiceProvider
    { 
        ///  
        /// Initializes a new System.Data.Services.ReflectionServiceProvider instance.
        ///  
        /// Metadata for this provider.
        /// instance of the data source provider.
        internal ReflectionServiceProvider(MetadataCacheItem metadata, object dataSourceInstance)
            : base(metadata, dataSourceInstance) 
        {
        } 
 
        /// Gets a value indicating whether null propagation is required in expression trees.
        public override bool NullPropagationRequired 
        {
            get { return true; }
        }
 
        /// 
        /// Provides a name for the context in which all resource containers are. 
        ///  
        public override string ResourceContextName
        { 
            get
            {
                return XmlConvert.EncodeName(this.Type.Name);
            } 
        }
 
        /// Gets the name of the container that holds this resource type.This method is called for open types only 
        /// Resource to get container for.
        ///  
        /// The name of the container for the specified resource; null if it cannot
        /// be determined.
        /// 
        public override ResourceContainer GetContainerForResourceType(Type resourceType) 
        {
            Debug.Assert(resourceType != null, "resourceType != null"); 
            return InternalGetContainerForResourceType(resourceType, this.EntitySets.Values); 
        }
 
        /// 
        /// Gets the container corresponding to the given navigation property
        /// The declaring type container name refers to the entity set that the declaring type belongs to
        ///  
        /// name of the entity container that the declaring type belongs to
        /// declaring type 
        /// resource navigation property 
        /// name of the container that this property refers to
        public override ResourceContainer GetContainer(string declaringTypeContainerName, Type declaringResourceType, ResourceProperty resourceProperty) 
        {
            Debug.Assert(declaringTypeContainerName != null, "declaringTypeContainerName != null");
            Debug.Assert(declaringResourceType != null, "declaringResourceType != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 
            return InternalGetContainerForResourceType(resourceProperty.ResourceClrType, this.EntitySets.Values);
        } 
 
        /// Gets the metadata document for this provider.
        /// Writer to which metadata XML should be written. 
        public override void GetMetadata(XmlWriter xmlWriter)
        {
            Debug.Assert(xmlWriter != null, "xmlWriter != null");
            TypeManager typeManager = new TypeManager(this.Types); 
            BaseServiceProvider.WriteTopLevelSchemaElements(xmlWriter);
            Dictionary associations = new Dictionary(StringComparer.Ordinal); 
            List typesInEntityContainerNamespace = null; 

            // Write the schema Element for every namespace 
            foreach (KeyValuePair> namespaceAlongWithTypes in typeManager.NamespaceAlongWithTypes)
            {
                // If the types live in the same namespace as that of entity container and types that don't live in any namespace,
                // should be written out in the service namespace. If the service type also doesn't have a namespace, we will use 
                // the service name as the namespace. See code below for that.
                if (namespaceAlongWithTypes.Key == this.Type.Namespace  || String.IsNullOrEmpty(namespaceAlongWithTypes.Key)) 
                { 
                    // We can't write the entity container until we have figured out all the associations.
                    // Hence storing the type information for types which live in the same namespace as that 
                    // of entity container and writting them at the end along with the entity container.
                    if (typesInEntityContainerNamespace == null)
                    {
                        typesInEntityContainerNamespace = namespaceAlongWithTypes.Value; 
                    }
                    else 
                    { 
                        typesInEntityContainerNamespace.AddRange(namespaceAlongWithTypes.Value);
                    } 
                }
                else
                {
                    var associationsInThisNamespace = new Dictionary(StringComparer.Ordinal); 
                    BaseServiceProvider.WriteSchemaElement(xmlWriter, namespaceAlongWithTypes.Key, this.CompatibleWithV1Schema);
                    WriteTypes(xmlWriter, namespaceAlongWithTypes.Value, associations, associationsInThisNamespace); 
                    WriteAssociations(xmlWriter, associationsInThisNamespace.Values); 
                    xmlWriter.WriteEndElement();
                } 
            }

            // Write the entity container definition. Also if there are types in the same namespace,
            // we need to write them out too. 
            string typeNamespace = this.Type.Namespace;
            if (String.IsNullOrEmpty(typeNamespace)) 
            { 
                typeNamespace = XmlConvert.EncodeName(this.Type.Name);
            } 

            BaseServiceProvider.WriteSchemaElement(xmlWriter, typeNamespace, this.CompatibleWithV1Schema);
            if (typesInEntityContainerNamespace != null)
            { 
                var associationsInThisNamespace = new Dictionary(StringComparer.Ordinal);
                WriteTypes(xmlWriter, typesInEntityContainerNamespace, associations, associationsInThisNamespace); 
                WriteAssociations(xmlWriter, associationsInThisNamespace.Values); 
            }
 
            this.WriteEntityContainer(xmlWriter, this.ResourceContextName, this.EntitySets, associations);
            xmlWriter.WriteEndElement();

            // These end elements balance the elements written out in WriteTopLevelSchemaElements 
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement(); 
            xmlWriter.Flush(); 
        }
 
        /// 
        /// Get the list of etag property names given the entity set name and the instance of the resource
        /// 
        /// name of the entity set 
        /// clr type of the resource whose etag properties need to be fetched
        /// list of etag property names 
        public override ICollection GetETagProperties(string containerName, Type resourceClrType) 
        {
            Debug.Assert(resourceClrType != null, "clrType cannot be null"); 
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(resourceClrType);
            Debug.Assert(resourceType != null, "resourceType != null");

            return resourceType.ETagProperties; 
        }
 
        ///  
        /// Checks whether the specified  is ordered.
        ///  
        /// Type to check.
        /// true if the type may be ordered; false otherwise.
        /// 
        /// The ordering may still fail at runtime; this method is currently 
        /// used for cleaner error messages only.
        ///  
        public override bool GetTypeIsOrdered(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 
            if (typeof(IComparable).IsAssignableFrom(type))
            {
                return true;
            } 
            else
            { 
                return base.GetTypeIsOrdered(type); 
            }
        } 

        #region IUpdatable Members

        ///  
        /// Creates the resource of the given type and belonging to the given container
        ///  
        /// container name to which the resource needs to be added 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and belonging to the given container 
        public override object CreateResource(string containerName, string fullTypeName)
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            { 
                object resource = ((IUpdatable)this.CurrentDataSource).CreateResource(containerName, fullTypeName);
                if (resource == null) 
                { 
                    throw new InvalidOperationException(Strings.BadProvider_CreateResourceReturnedNull);
                } 

                return resource;
            }
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            } 
        }
 
        /// 
        /// Gets the resource of the given type that the query points to
        /// 
        /// query pointing to a particular resource 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and as referenced by the query 
        public override object GetResource(IQueryable query, string fullTypeName) 
        {
            object resource = null; 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                try
                { 
                    resource = ((IUpdatable)this.CurrentDataSource).GetResource(query, fullTypeName);
                } 
                catch (ArgumentException e) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidUriSpecified, e); 
                }
            }
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
 
            return resource;
        } 

        /// 
        /// Resets the value of the given resource to its default value
        ///  
        /// resource whose value needs to be reset
        /// same resource with its value reset 
        public override object ResetResource(object resource) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            {
                resource = ((IUpdatable)this.CurrentDataSource).ResetResource(resource);
            }
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            } 

            return resource; 
        }

        /// 
        /// Sets the value of the given property on the target object 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// value of the property
        public override void SetValue(object targetResource, string propertyName, object propertyValue) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).SetValue(targetResource, propertyName, propertyValue); 
            }
            else 
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
        }

        /// 
        /// Gets the value of the given property on the target object 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// the value of the property for the given target resource
        public override object GetValue(object targetResource, string propertyName) 
        {
            object resource = null;
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            { 
                resource = ((IUpdatable)this.CurrentDataSource).GetValue(targetResource, propertyName);
            } 
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }

            if (resource == null)
            { 
                throw DataServiceException.CreateResourceNotFound(propertyName);
            } 
 
            return resource;
        } 

        /// 
        /// Sets the value of the given reference property on the target object
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property 
        public override void SetReference(object targetResource, string propertyName, object propertyValue)
        { 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).SetReference(targetResource, propertyName, propertyValue);
            } 
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }
        } 

        /// 
        /// Adds the given value to the collection
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be added 
        public override void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
        { 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).AddReferenceToCollection(targetResource, propertyName, resourceToBeAdded);
            } 
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }
        } 

        /// Applies expansions to the specified .
        ///  object to expand.
        /// A collection of ordered  paths. 
        /// 
        /// An  object of the same type as the given , 
        /// with the results including the specified . 
        /// 
        ///  
        /// This method may modify the  to indicate which expansions
        /// are included.
        ///
        /// The returned  may implement the  
        /// interface to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects. 
        ///  
        public override IEnumerable ApplyExpansions(IQueryable queryable, ICollection expandPaths)
        { 
            IExpandProvider provider = this.CurrentDataSource as IExpandProvider;
            if (provider != null)
            {
                return provider.ApplyExpansions(queryable, expandPaths); 
            }
            else 
            { 
                foreach (ExpandSegmentCollection path in expandPaths)
                { 
                    if (path.HasFilter)
                    {
                        return new BasicExpandProvider(this, true).ApplyExpansions(queryable, expandPaths);
                    } 
                }
 
                // This pass-through implementation is appropriate for providers that fault-in on demand. 
                return queryable;
            } 
        }

        /// 
        /// Removes the given value from the collection 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be removed
        public override void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).RemoveReferenceFromCollection(targetResource, propertyName, resourceToBeRemoved); 
            }
            else 
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
        }

        /// 
        /// Delete the given resource 
        /// 
        /// resource that needs to be deleted 
        public override void DeleteResource(object targetResource) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            {
                ((IUpdatable)this.CurrentDataSource).DeleteResource(targetResource);
            }
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            } 
        }
 
        /// 
        /// Saves all the pending changes made till now
        /// 
        public override void SaveChanges() 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            { 
                ((IUpdatable)this.CurrentDataSource).SaveChanges();
            } 
            else
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
        }
 
        ///  
        /// Returns the actual instance of the resource represented by the given resource object
        ///  
        /// object representing the resource whose instance needs to be fetched
        /// The actual instance of the resource represented by the given resource object
        public override object ResolveResource(object resource)
        { 
            object resolvedResource = null;
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            { 
                resolvedResource = ((IUpdatable)this.CurrentDataSource).ResolveResource(resource);
            } 
            else
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 

            if (resolvedResource == null) 
            { 
                throw new InvalidOperationException(Strings.BadProvider_ResolveResourceReturnedNull);
            } 

            return resolvedResource;
        }
 
        /// 
        /// Revert all the pending changes. 
        ///  
        public override void ClearChanges()
        { 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).ClearChanges();
            } 
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }
        } 

        #endregion

        /// Checks whether the given property is a key property. 
        /// property to check
        /// returns the key kind of the property, based on the heuristic it matches 
        /// true if this is a key property, else returns false 
        internal static bool IsPropertyKeyProperty(PropertyInfo property, out ResourceKeyKind keyKind)
        { 
            keyKind = (ResourceKeyKind)(-1);

            // Only primitive types are allowed to be keys.
            // Checks for generic to exclude Nullable<> value-type primitives, since we don't allows keys to be null. 
            if (WebUtil.IsPrimitiveType(property.PropertyType) &&
                !property.PropertyType.IsGenericType) 
            { 
                DataServiceKeyAttribute keyAttribute = property.ReflectedType.GetCustomAttributes(true).OfType().FirstOrDefault();
                if (keyAttribute != null && keyAttribute.KeyNames.Contains(property.Name)) 
                {
                    keyKind = ResourceKeyKind.AttributedKey;
                    return true;
                } 

                // For now, the key property must be {TypeName}Id or Id and the property 
                // type must be primitive, since we do not support non-primitive types 
                // as keys
                if (property.Name == property.DeclaringType.Name + "ID") 
                {
                    keyKind = ResourceKeyKind.TypeNameId;
                    return true;
                } 
                else if (property.Name == "ID")
                { 
                    keyKind = ResourceKeyKind.Id; 
                    return true;
                } 
            }

            return false;
        } 

#if ASTORIA_CONTAINMENT 
 
        /// 
        /// Returns an object that can enumerate all  
        /// instances that apply to this model.
        /// 
        /// 
        /// An object that can enumerate all  
        /// instances that apply to this model.
        ///  
        protected override IEnumerable EnumerateAccessPathAttributes() 
        {
            Type provider = this.Type; 
            foreach (ResourceContainer container in this.EntitySets.Values)
            {
                PropertyInfo property = provider.GetProperty(container.Name, WebUtil.PublicInstanceBindingFlags);
                Debug.Assert(property != null, "property != null -- otherwise " + container.Name + " shouldn't be in metadata."); 
                object[] attributes = property.GetCustomAttributes(true);
                if (attributes == null || attributes.Length == 0) 
                { 
                    continue;
                } 

                foreach (AccessPathAttribute attribute in attributes.OfType())
                {
                    attribute.AnnotatedContainer = container; 
                    yield return attribute;
                } 
            } 
        }
 
#endif

        /// Populates the metadata for this provider.
        ///  
        /// Dictionary of known CLR to ResourceType entries, which is
        /// populated as metadata is built. 
        ///  
        /// 
        /// Dictionary of name to ResourceContainer for entity sets, populated 
        /// as metadata is built.
        /// 
        protected override void PopulateMetadata(
            IDictionary knownTypes, IDictionary entitySets) 
        {
            Queue unvisitedTypes = new Queue(); 
 
            // Get the list of properties to be ignored.
            List propertiesToBeIgnored = new List( 
                IgnorePropertiesAttribute.GetProperties(this.Type, true /*inherit*/, WebUtil.PublicInstanceBindingFlags));
            PropertyInfo[] properties = this.Type.GetProperties(WebUtil.PublicInstanceBindingFlags);
            foreach (PropertyInfo property in properties)
            { 
                if (!propertiesToBeIgnored.Contains(property.Name) && property.CanRead && property.GetIndexParameters().Length == 0)
                { 
                    Type elementType = BaseServiceProvider.GetIQueryableElement(property.PropertyType); 
                    if (elementType != null)
                    { 
                        // If the element type has key defined (in itself or one of its ancestors)
                        ResourceType resourceType = BuildHierarchyForEntityType(elementType, knownTypes, unvisitedTypes, true /* entity type candidate */);
                        if (resourceType != null)
                        { 
                            // We do not allow MEST scenaria for reflection provider
                            foreach (KeyValuePair entitySetInfo in entitySets) 
                            { 
                                Type entitySetType = entitySetInfo.Value.ElementType;
                                if (entitySetType.IsAssignableFrom(elementType)) 
                                {
                                    throw new InvalidOperationException(Strings.ReflectionProvider_MultipleEntitySetsForSameType(entitySetInfo.Value.Name, property.Name, entitySetType.FullName, resourceType.FullName));
                                }
                                else if (elementType.IsAssignableFrom(entitySetType)) 
                                {
                                    throw new InvalidOperationException(Strings.ReflectionProvider_MultipleEntitySetsForSameType(property.Name, entitySetInfo.Value.Name, resourceType.FullName, entitySetType.FullName)); 
                                } 
                            }
 
                            // Add the entity set to the list of entity sets.
                            ResourceContainer resourceContainer = new ResourceContainer(property.Name, resourceType);
                            entitySets.Add(property.Name, resourceContainer);
                        } 
                        else
                        { 
                            throw new InvalidOperationException(Strings.ReflectionProvider_InvalidEntitySetProperty(property.Name, this.ResourceContextName)); 
                        }
                    } 
                }
            }

            // Populate the metadata for all the types in unvisited types 
            // and also their properties and populates metadata about property types
            PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets.Values); 
 
            // At this point, we should have all the top level entity types and the complex types
            PopulateMetadataForDerivedTypes(knownTypes, unvisitedTypes, entitySets.Values); 
        }

        /// 
        /// Creates the IQueryable instance for the given resource container and returns it 
        /// 
        /// resource container for which IQueryable instance needs to be created 
        /// returns the IQueryable instance for the given resource container 
        protected override IQueryable GetResourceContainerInstance(ResourceContainer resourceContainer)
        { 
            Debug.Assert(resourceContainer != null, "resourceContainer != null");
            if (resourceContainer.ReadFromContextDelegate == null)
            {
                PropertyInfo propertyInfo = this.Type.GetProperty(resourceContainer.Name, WebUtil.PublicInstanceBindingFlags); 
                MethodInfo getValueMethod = propertyInfo.GetGetMethod();
 
                // return ((TheContext)arg0).get_Property(); 
                Type[] parameterTypes = new Type[] { typeof(object) };
                System.Reflection.Emit.DynamicMethod readerMethod = new System.Reflection.Emit.DynamicMethod("queryable_reader", typeof(IQueryable), parameterTypes, false); 
                var generator = readerMethod.GetILGenerator();
                generator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
                generator.Emit(System.Reflection.Emit.OpCodes.Castclass, this.Type);
                generator.Emit(System.Reflection.Emit.OpCodes.Call, getValueMethod); 
                generator.Emit(System.Reflection.Emit.OpCodes.Ret);
                resourceContainer.ReadFromContextDelegate = (Func)readerMethod.CreateDelegate(typeof(Func)); 
            } 

            Debug.Assert(resourceContainer.ReadFromContextDelegate != null, "resourceContainer.ReadFromContextDelegate != null"); 
            return resourceContainer.ReadFromContextDelegate(this.CurrentDataSource);
        }

        ///  
        /// Populate types for metadata specified by the provider
        ///  
        /// list of types specified by the provider 
        /// list of already known types
        /// list of entity sets as specified in the data source type 
        protected override void PopulateMetadataForUserSpecifiedTypes(
            IEnumerable userSpecifiedTypes, IDictionary knownTypes, IEnumerable entitySets)
        {
            Queue unvisitedTypes = new Queue(); 
            foreach (Type type in userSpecifiedTypes)
            { 
                ResourceType resourceType; 
                if (knownTypes.TryGetValue(type, out resourceType))
                { 
                    continue;
                }

                if (IsEntityOrComplexType(type, knownTypes, unvisitedTypes) == null) 
                {
                    throw new InvalidOperationException(Strings.BadProvider_InvalidTypeSpecified(type.FullName)); 
                } 
            }
 
            PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets);
        }

        ///  
        /// Populate metadata for the given clr type.
        ///  
        /// type whose metadata needs to be loaded. 
        /// list of already known resource types.
        /// list of entity sets as specified in the data source. 
        /// resource type containing metadata for the given clr type.
        protected override ResourceType PopulateMetadataForType(Type type, IDictionary knownTypes, IEnumerable entitySets)
        {
            Queue unvisitedTypes = new Queue(); 
            ResourceType resourceType;
            if (!knownTypes.TryGetValue(type, out resourceType)) 
            { 
                resourceType = IsEntityOrComplexType(type, knownTypes, unvisitedTypes);
                if (resourceType != null) 
                {
                    PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets);
                }
            } 

            return resourceType; 
        } 

        /// Checks whether the specified type is a complex type. 
        /// Type to check.
        /// 
        /// true if the specified type is a complex type; false otherwise. Note
        /// that resources are not distinguished from complex types. 
        /// 
        private static bool IsComplexType(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
 
            // Complex types are all types that contain public properties of primitive
            // types.
            //
            // We purposefully ignore certain known classes which fit this description 
            // but we know are not meaningful for Astoria:
            // - System.Array:  what would get serialized would be Length, IsFixed, etc. 
            // - Pointers:      we would otherwise serialize the pointer size 
            // - COM object wrappers
            // - interface: since we will never know what the exact type of the instance will be. 
            if (!type.IsVisible || type.IsArray || type.IsPointer || type.IsCOMObject || type.IsInterface ||
                type == typeof(IntPtr) || type == typeof(UIntPtr) || type == typeof(char) ||
                type == typeof(TimeSpan) || type == typeof(DateTimeOffset) || type == typeof(Uri) ||
                type.IsEnum) 
            {
                return false; 
            } 

            // For nullable types, we care whether the underlying value type is 
            // complex type.
            Type nullableUnderlyingType = Nullable.GetUnderlyingType(type);
            if (nullableUnderlyingType != null)
            { 
                return ReflectionServiceProvider.IsComplexType(nullableUnderlyingType);
            } 
 
            return true;
        } 

        /// 
        /// Checks whether there is a key defined for the given type.
        ///  
        /// type to check 
        ///  
        /// Whether  is being considered as a possible 
        /// entity type.
        ///  
        /// returns true if there are one or key properties present else returns false
        private static bool DoesTypeHaveKeyProperties(Type type, bool entityTypeCandidate)
        {
            Debug.Assert(type != null, "type != null"); 

            // Check for properties declared on this element only 
            foreach (PropertyInfo property in type.GetProperties(WebUtil.PublicInstanceBindingFlags | BindingFlags.DeclaredOnly)) 
            {
                ResourceKeyKind keyKind; 
                if (IsPropertyKeyProperty(property, out keyKind))
                {
                    if (keyKind == ResourceKeyKind.AttributedKey && !entityTypeCandidate)
                    { 
                        throw new InvalidOperationException(Strings.ReflectionProvider_EntityTypeHasKeyButNoEntitySet(type.FullName));
                    } 
 
                    if (!entityTypeCandidate)
                    { 
                        return false;
                    }

                    return true; 
                }
            } 
 
            return false;
        } 

        /// 
        /// Populates the metadata for the given unvisited types and all the associated types with this type
        ///  
        /// list of known types
        /// list of unvisited type 
        /// Available entity sets. 
        private static void PopulateMetadataForTypes(
            IDictionary knownTypes, 
            Queue unvisitedTypes,
            IEnumerable entitySets)
        {
            Debug.Assert(knownTypes != null, "knownTypes != null"); 
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null"); 
 
            // Start walking down all the types
            while (unvisitedTypes.Count != 0) 
            {
                // get the unvisited element
                ResourceType type = unvisitedTypes.Dequeue();
 
                // Go through all the properties and find out one or more complex types
                BuildTypeProperties(type, knownTypes, unvisitedTypes, entitySets); 
            } 
        }
 
        /// 
        /// Walks through the list of ancestors and finds the root base type and collects metadata for the entire chain of ancestors
        /// 
        /// type whose ancestors metadata needs to be populated 
        /// list of already known types
        /// list of unvisited types 
        /// Whether  is a candidate to be an entity type. 
        /// return true if this given type is a entity type, otherwise returns false
        private static ResourceType BuildHierarchyForEntityType( 
            Type type, IDictionary knownTypes, Queue unvisitedTypes, bool entityTypeCandidate)
        {
            List ancestors = new List();
 
            if (!type.IsVisible)
            { 
                return null; 
            }
 
            Type baseType = type;
            ResourceType baseResourceType = null;

            // Since this method is also used on property types, which can be interfaces, 
            // Base types can be null
            while (baseType != null) 
            { 
                // Try and check if the base type is already loaded
                if (knownTypes.TryGetValue(baseType, out baseResourceType)) 
                {
                    break;
                }
 
                ancestors.Add(baseType);
                baseType = baseType.BaseType; 
            } 

            if (baseResourceType == null) 
            {
                // If entityTypeCandidate is false, then it means that the current type can't
                // be a entity type with keys. In other words, it must derive from an existing
                // type. Otherwise, its not an entity type 
                if (entityTypeCandidate == false)
                { 
                    return null; 
                }
 
                // Find the last ancestor which has key defined
                for (int i = ancestors.Count - 1; i >= 0; i--)
                {
                    if (DoesTypeHaveKeyProperties(ancestors[i], entityTypeCandidate)) 
                    {
                        break; 
                    } 

                    // Else this type is not interesting. Remove it from the ancestors list 
                    ancestors.RemoveAt(i);
                }
            }
            else if (baseResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) 
            {
                return null; 
            } 
            else if (ancestors.Count == 0)
            { 
                // we might have found the top level element.So just return
                return baseResourceType;
            }
 
            // For all the valid ancestors, add the type to the list of types encountered
            // and unvisited types 
            // its important that we enqueue the ancestors first, since when we populate member metadata 
            // we can make sure that the base type is fully populated
            for (int i = ancestors.Count - 1; i >= 0; i--) 
            {
                ResourceType entityType = new ResourceType(ancestors[i], ResourceTypeKind.EntityType, baseResourceType);
                unvisitedTypes.Enqueue(entityType);
                knownTypes.Add(ancestors[i], entityType); 
                baseResourceType = entityType;
            } 
 
            return baseResourceType;
        } 

        /// 
        /// Populates the metadata for the properties of the given resource type
        ///  
        /// resource type whose properties metadata needs to be populated
        /// list of known types 
        /// list of unvisited type 
        /// Available entity sets.
        private static void BuildTypeProperties( 
            ResourceType parentResourceType,
            IDictionary knownTypes,
            Queue unvisitedTypes,
            IEnumerable 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 propertiesToBeIgnored = new HashSet(StringComparer.Ordinal);
#if ASTORIA_OPEN_OBJECT
            if (parentResourceType.IsOpenType)
            { 
                propertiesToBeIgnored.Add(OpenTypeAttribute.GetOpenPropertyName(parentResourceType.Type));
            } 
#endif 

            foreach (string propertyName in IgnorePropertiesAttribute.GetProperties(parentResourceType.Type, false /*inherit*/, bindingFlags)) 
            {
                propertiesToBeIgnored.Add(propertyName);
            }
 
            ResourceKeyKind keyKind = (ResourceKeyKind)Int32.MaxValue;
            PropertyInfo[] properties = parentResourceType.Type.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 = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
                    ResourceContainer container = null;
                    bool collection = false; 

                    if (!knownTypes.TryGetValue(resourcePropertyType, out resourceType)) 
                    { 
                        Type collectionType = GetIEnumerableElement(property.PropertyType);
                        if (collectionType != null) 
                        {
                            knownTypes.TryGetValue(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 != null)
                                    { 
                                        // 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, 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) 
                        {
                            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);
                        Debug.Assert(container != null, "container != null");
                    } 

                    ResourceProperty resourceProperty = new ResourceProperty(property, kind, MimeTypeAttribute.GetMemberMimeType(property), resourceType, container); 
                    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)); 
            }

            parentResourceType.SortKeyMembers();
            LoadETagProperties(parentResourceType); 
        }
 
        ///  
        /// If the given type is a entity or complex type, it returns the resource type corresponding to the given type
        ///  
        /// clr type
        /// list of already known types
        /// list of unvisited types
        /// resource type corresponding to the given clr type, if the clr type is entity or complex 
        private static ResourceType IsEntityOrComplexType(Type type, IDictionary knownTypes, Queue unvisitedTypes)
        { 
            // Ignore values types here. We do not support resources of values type (entity or complex) 
            if (type.IsValueType)
            { 
                return null;
            }

            ResourceType resourceType = BuildHierarchyForEntityType(type, knownTypes, unvisitedTypes, false /* entityTypeCandidate */); 
            if (resourceType == null && IsComplexType(type))
            { 
                resourceType = new ResourceType(type, ResourceTypeKind.ComplexType); 
                knownTypes.Add(type, resourceType);
                unvisitedTypes.Enqueue(resourceType); 
            }

            return resourceType;
        } 

        /// Get the resource container for the given clr type. 
        /// clr type for which resource container name needs to be returned 
        /// Available entity sets to consider.
        /// The container for its type, null if not found. 
        private static ResourceContainer InternalGetContainerForResourceType(Type type, IEnumerable entitySets)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(entitySets != null, "entitySets != null"); 

            // For each entity set, find out which one matches the type of this resource 
            foreach (ResourceContainer entitySetInfo in entitySets) 
            {
                if (entitySetInfo.ElementType.IsAssignableFrom(type)) 
                {
                    return entitySetInfo;
                }
            } 

            return null; 
        } 

        ///  
        /// Find out all the derived types in the list of assemblies and then populate metadata for those types
        /// 
        /// list of known types
        /// list of unvisited types 
        /// Available entity sets.
        private static void PopulateMetadataForDerivedTypes( 
            IDictionary knownTypes, Queue unvisitedTypes, IEnumerable entitySets) 
        {
            Debug.Assert(knownTypes != null, "knownTypes != null"); 
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null");

            // Find all the root resource entity types 
            List rootTypes = new List();
            foreach (ResourceType resourceType in knownTypes.Values) 
            { 
                if (resourceType.BaseType == null &&
                    resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) 
                {
                    rootTypes.Add(resourceType);
                }
            } 

            // Use the default comparer, which calls Assembly.Equals (not a simple reference comparison). 
            HashSet assemblies = new HashSet(EqualityComparer.Default); 
            List derivedTypes = new List();
 
            // Walk through all the types in the assemblies and find all the derived types
            foreach (ResourceType resourceType in knownTypes.Values)
            {
                // No need to look into primitive types, as these live in system assemblies. 
                if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                { 
                    continue; 
                }
 
                Assembly assembly = resourceType.Type.Assembly;
                //// ignore if the assembly has already been scanned
                if (assemblies.Contains(assembly))
                { 
                    continue;
                } 
 
                // Walk all the types in that assembly
                foreach (Type type in assembly.GetTypes()) 
                {
                    // skip all the non visible types
                    if (!type.IsVisible)
                    { 
                        continue;
                    } 
 
                    // Skip the type if its already loaded
                    if (knownTypes.ContainsKey(type)) 
                    {
                        continue;
                    }
 
                    // Check if this type dervies from any one of the root types
                    for (int i = 0; i < rootTypes.Count; i++) 
                    { 
                        if (rootTypes[i].Type.IsAssignableFrom(type))
                        { 
                            derivedTypes.Add(type);
                        }
                    }
                } 

                assemblies.Add(assembly); 
            } 

            foreach (Type type in derivedTypes) 
            {
                BuildHierarchyForEntityType(type, knownTypes, unvisitedTypes, false /* entityTypeCandidate */);
                PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets);
            } 
        }
 
        ///  
        /// Write the facets for clr types
        ///  
        /// XmlWriter in which facets needs to be written
        /// property which contains the primitive type for which facets needs to be written
        private static void WritePrimitivePropertyFacets(XmlWriter xmlWriter, ResourceProperty resourceProperty)
        { 
            Debug.Assert(
                resourceProperty.IsOfKind(ResourcePropertyKind.Primitive), 
                "property must be of primitive type"); 

            bool nullable = true; 
            Type propertyType = resourceProperty.Type;

            // Key properties can't be nullable and can't be generic
            if (!resourceProperty.IsOfKind(ResourcePropertyKind.Key)) 
            {
                if (propertyType.IsGenericType && 
                    resourceProperty.Type.GetGenericTypeDefinition() == typeof(Nullable<>)) 
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType); 
                }
                else if (propertyType.IsValueType)
                {
                    nullable = false; 
                }
            } 
            else 
            {
                nullable = false; 
            }

            xmlWriter.WriteAttributeString(XmlConstants.Nullable, nullable ? XmlConstants.XmlTrueLiteral : XmlConstants.XmlFalseLiteral);
        } 

        ///  
        /// Write the metadata for the entityType in the xmlWriter 
        /// 
        /// xmlWriter in which metadata needs to be written 
        /// entityType whose metadata needs to be written
        /// list of associations present in the model.
        /// list of associations in the current namespace.
        private static void WriteEntityType( 
            XmlWriter xmlWriter,
            ResourceType entityType, 
            Dictionary associations, 
            Dictionary associationsInThisNamespace)
        { 
            Debug.Assert(xmlWriter != null, "XmlWriter cannot be null");
            Debug.Assert(entityType.ResourceTypeKind == ResourceTypeKind.EntityType, "Type must be entityType");

            xmlWriter.WriteStartElement(XmlConstants.EntityType); 
            xmlWriter.WriteAttributeString(XmlConstants.Name, XmlConvert.EncodeName(entityType.Name));
 
            if (entityType.Type.IsAbstract) 
            {
                xmlWriter.WriteAttributeString(XmlConstants.Abstract, "true"); 
            }

#if ASTORIA_OPEN_OBJECT
            if (entityType.IsOpenType && OpenTypeAttribute.DeclaresOpenType(entityType.Type)) 
            {
                xmlWriter.WriteAttributeString( 
                    XmlConstants.DataWebOpenTypeAttributeName, 
                    XmlConstants.DataWebNamespace,
                    OpenTypeAttribute.GetOpenPropertyName(entityType.Type)); 
            }
#endif

            if (entityType.BaseType != null) 
            {
                xmlWriter.WriteAttributeString(XmlConstants.BaseType, XmlConvert.EncodeName(entityType.BaseType.FullName)); 
            } 
            else
            { 
                xmlWriter.WriteStartElement(XmlConstants.Key);
                foreach (ResourceProperty property in entityType.KeyProperties)
                {
                    xmlWriter.WriteStartElement(XmlConstants.PropertyRef); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, property.Name);
                    xmlWriter.WriteEndElement(); 
                } 

                xmlWriter.WriteEndElement(); 
            }

            WriteProperties(xmlWriter, entityType, associations, associationsInThisNamespace);
            xmlWriter.WriteEndElement(); 
        }
 
        ///  
        /// Write the metadata for the complexType in the xmlWriter
        ///  
        /// xmlWriter in which metadata needs to be written
        /// complexType whose metadata needs to be written
        private static void WriteComplexType(XmlWriter xmlWriter, ResourceType complexType)
        { 
            Debug.Assert(xmlWriter != null, "XmlWriter cannot be null");
            Debug.Assert(complexType.ResourceTypeKind == ResourceTypeKind.ComplexType, "Type must be complexType"); 
 
            xmlWriter.WriteStartElement(XmlConstants.ComplexType);
            xmlWriter.WriteAttributeString(XmlConstants.Name, XmlConvert.EncodeName(complexType.Name)); 
            WriteProperties(xmlWriter, complexType, null, null);
            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Write the metadata of all the properties for the given typein the xmlWriter 
        ///  
        /// xmlWriter in which metadata needs to be written
        /// resource type whose property metadata needs to be written 
        /// list of associations present in the model.
        /// list of associations in the current namespace.
        private static void WriteProperties(
            XmlWriter xmlWriter, 
            ResourceType type,
            Dictionary associations, 
            Dictionary associationsInThisNamespace) 
        {
            Debug.Assert(xmlWriter != null, "xmlWriter != null"); 
            Debug.Assert(type != null, "type != null");
            for (int i = 0; i < type.PropertiesDeclaredInThisType.Count; i++)
            {
                ResourceProperty resourceProperty = type.PropertiesDeclaredInThisType[i]; 
                string elementName;
 
                // For primitive types, get the corresponding edm typename 
                if (resourceProperty.TypeKind == ResourceTypeKind.Primitive)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.Property);
                    xmlWriter.WriteAttributeString(XmlConstants.Name, resourceProperty.Name);
                    elementName = WebUtil.GetEdmTypeName(resourceProperty.Type);
                    xmlWriter.WriteAttributeString(XmlConstants.Type, elementName); 
                    WritePrimitivePropertyFacets(xmlWriter, resourceProperty);
                    if (!String.IsNullOrEmpty(resourceProperty.MimeType)) 
                    { 
                        BaseServiceProvider.WriteDataWebMetadata(xmlWriter, XmlConstants.DataWebMimeTypeAttributeName, resourceProperty.MimeType);
                    } 

                    if (type.ResourceTypeKind == ResourceTypeKind.EntityType &&
                        type.ETagProperties.Contains(resourceProperty))
                    { 
                        xmlWriter.WriteAttributeString(XmlConstants.ConcurrencyAttribute, XmlConstants.ConcurrencyFixedValue);
                    } 
                } 
                else if (resourceProperty.Kind == ResourcePropertyKind.ComplexType)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.Property);
                    xmlWriter.WriteAttributeString(XmlConstants.Name, resourceProperty.Name);
                    elementName = resourceProperty.ResourceType.FullName;
                    xmlWriter.WriteAttributeString(XmlConstants.Type, elementName); 

                    // Edm doesn't support nullable complex type properties 
                    xmlWriter.WriteAttributeString(XmlConstants.Nullable, XmlConstants.XmlFalseLiteral); 
                }
                else 
                {
                    Debug.Assert(
                        ResourceTypeKind.EntityType == resourceProperty.TypeKind,
                        "Unexpected property type kind"); 
                    bool multivalued = false;
 
                    xmlWriter.WriteStartElement(XmlConstants.NavigationProperty); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, resourceProperty.Name);
                    elementName = resourceProperty.ResourceType.FullName; 
                    if (resourceProperty.Kind == ResourcePropertyKind.ResourceSetReference)
                    {
                        multivalued = true;
                    } 

                    // for every nav property, add a new association to the metadata 
                    // the name of the assocation will be _ 
                    // there might be conflicts since there can be 2 types with the same name, but in different namespace.
                    // in that case, we will use the full type name (replace '.' by '_'). That should make it unique. 
                    string associationName = type.Name + '_' + resourceProperty.Name;
                    if (associations.ContainsKey(associationName))
                    {
                        associationName = type.FullName.Replace('.', '_') + '_' + resourceProperty.Name; 
                    }
 
                    AssociationInfo association = new AssociationInfo( 
                        associationName,
                        type.Type.Namespace, 
                        new EndInfo(resourceProperty.Name, resourceProperty.ResourceType, multivalued ? XmlConstants.Many : XmlConstants.ZeroOrOne),
                        new EndInfo(type.Name, type, XmlConstants.Many));

                    // Add it to both the global list and the current namespace list. 
                    associationsInThisNamespace.Add(associationName, association);
                    associations.Add(associationName, association); 
 
                    xmlWriter.WriteAttributeString(XmlConstants.Relationship, association.FullName);
                    xmlWriter.WriteAttributeString(XmlConstants.FromRole, type.Name); 
                    xmlWriter.WriteAttributeString(XmlConstants.ToRole, resourceProperty.Name);

#if ASTORIA_CONTAINMENT
 
                    if (resourceProperty.ContainmentTarget != null)
                    { 
                        string path = resourceProperty.ContainmentTargetCanonical ? 
                            XmlConstants.DataWebAccessPathCanonicalValue :
                            XmlConstants.DataWebAccessPathNonCanonicalValue; 
                        BaseServiceProvider.WriteDataWebMetadata(xmlWriter, XmlConstants.DataWebAccessPathAttribute, path);
                        BaseServiceProvider.WriteDataWebMetadata(
                            xmlWriter, XmlConstants.DataWebAccessPathTargetAttribute, resourceProperty.ContainmentTarget.Name);
                        BaseServiceProvider.WriteDataWebMetadata( 
                            xmlWriter, XmlConstants.DataWebAccessPathChildKeysAttribute, string.Join(",", resourceProperty.ContainmentChildKeys));
                        BaseServiceProvider.WriteDataWebMetadata( 
                            xmlWriter, XmlConstants.DataWebAccessPathParentKeysAttribute, string.Join(",", resourceProperty.ContainmentParentKeys)); 
                    }
 
#endif
                }

                xmlWriter.WriteEndElement(); 
            }
        } 
 
        /// 
        /// Writes the definition of types in the XmlWriter 
        /// 
        /// xmlWriter in which metadata needs to be written
        /// resourceTypes whose metadata needs to be written
        /// list of associations present in the model. 
        /// list of associations in the current namespace.
        private static void WriteTypes( 
            XmlWriter xmlWriter, 
            List types,
            Dictionary associations, 
            Dictionary associationsInThisNamespace)
        {
            foreach (ResourceType type in types)
            { 
                if (ResourceTypeKind.EntityType == type.ResourceTypeKind)
                { 
                    WriteEntityType(xmlWriter, type, associations, associationsInThisNamespace); 
                }
                else 
                {
                    Debug.Assert(ResourceTypeKind.ComplexType == type.ResourceTypeKind, "this must be a complex type");
                    WriteComplexType(xmlWriter, type);
                } 
            }
        } 
 
        /// 
        /// Loads the etag properties for the given resource type 
        /// 
        /// resource type whose etag property names need to be loaded.
        private static void LoadETagProperties(ResourceType resourceType)
        { 
            // if it is the root type, then we need to inherit the attribute from the base type.
            // otherwise, we need not, since if the base type already has it, the appropriate properties 
            // must already have been marked as concurrency properties. 
            bool inherit = resourceType.BaseType == null;
 
            // Read the etag attribute from the type and return it
            ETagAttribute[] attributes = (ETagAttribute[])resourceType.Type.GetCustomAttributes(typeof(ETagAttribute), inherit);
            Debug.Assert(attributes.Length <= 1, "Only one attribute can be specified per type");
 
            if (attributes.Length == 1)
            { 
                // Validate the property names 
                // we may need to cache them instead of reading them everytime
                foreach (string propertyName in attributes[0].PropertyNames) 
                {
                    ResourceProperty property = resourceType.TryResolvePropertyNameDefinedInThisType(propertyName);
                    if (property == null)
                    { 
                        throw new InvalidOperationException(Strings.ETagAttribute_PropertyNameNotValid(propertyName, resourceType.FullName));
                    } 
 
                    if (property.TypeKind != ResourceTypeKind.Primitive)
                    { 
                        throw new InvalidOperationException(Strings.ETagAttribute_ETagPropertiesMustBeOfPrimitiveType(propertyName, resourceType.FullName));
                    }

                    // Ignore key properties if they are part of etag, since the uri already has the key information 
                    // and it makes no sense to duplicate them in etag
                    if (property.IsOfKind(ResourcePropertyKind.Key)) 
                    { 
                        throw new InvalidOperationException(Strings.ETagAttribute_KeyPropertiesCannotBePartOfETag(propertyName, resourceType.FullName));
                    } 

                    resourceType.AddETagProperty(property);
                }
            } 
        }
 
        ///  
        /// Writes the metadata for the given associations.
        ///  
        /// xmlWriter in which metadata needs to be written.
        /// associations whose metadata need to be written.
        private static void WriteAssociations(XmlWriter xmlWriter, IEnumerable associations)
        { 
            foreach (AssociationInfo association in associations)
            { 
                xmlWriter.WriteStartElement(XmlConstants.Association); 
                xmlWriter.WriteAttributeString(XmlConstants.Name, association.Name);
 
                foreach (EndInfo endInfo in association.Ends)
                {
                    xmlWriter.WriteStartElement(XmlConstants.End);
                    xmlWriter.WriteAttributeString(XmlConstants.Role, endInfo.Name); 

                    // The ends are of reference type 
                    xmlWriter.WriteAttributeString(XmlConstants.Type, endInfo.Type.FullName); 

                    // Write the multiplicity value 
                    xmlWriter.WriteAttributeString(XmlConstants.Multiplicity, endInfo.Multiplicity);
                    xmlWriter.WriteEndElement();
                }
 
                xmlWriter.WriteEndElement();
            } 
        } 

        ///  
        /// Writes the metadata for association sets for the given associations.
        /// 
        /// xmlWriter in which metadata needs to be written
        /// associations for which association sets needs to be written. 
        private void WriteAssociationSets(XmlWriter xmlWriter, IEnumerable associations)
        { 
            foreach (AssociationInfo association in associations) 
            {
                xmlWriter.WriteStartElement(XmlConstants.AssociationSet); 
                xmlWriter.WriteAttributeString(XmlConstants.Name, association.Name);
                xmlWriter.WriteAttributeString(XmlConstants.Association, association.FullName);
                foreach (EndInfo endInfo in association.Ends)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.End);
                    xmlWriter.WriteAttributeString(XmlConstants.Role, endInfo.Name); 
 
                    // The ends are of reference type
                    ResourceContainer container = this.GetContainerForResourceType(endInfo.Type.Type); 
                    xmlWriter.WriteAttributeString(XmlConstants.EntitySet, container.Name);
                    xmlWriter.WriteEndElement();
                }
 
                xmlWriter.WriteEndElement();
            } 
        } 

        ///  
        /// Writes the entity container definition
        /// 
        /// xmlWriter into which metadata is written
        /// name of the entity container 
        /// list of entity set name and containing element type name
        /// associations for which association sets metadata needs to be written. 
        private void WriteEntityContainer( 
            XmlWriter xmlWriter,
            string entityContainerName, 
            IEnumerable> entitySets,
            Dictionary associations)
        {
            xmlWriter.WriteStartElement(XmlConstants.EntityContainer); 
            xmlWriter.WriteAttributeString(XmlConstants.Name, entityContainerName);
 
            // Since reflection based provider supports only one entity container, we should write the 
            // default entity container attribute for the only entity container
            BaseServiceProvider.WriteDataWebMetadata(xmlWriter, XmlConstants.IsDefaultEntityContainerAttribute, XmlConstants.XmlTrueLiteral); 

            foreach (KeyValuePair entitySet in entitySets)
            {
                ResourceContainer container = entitySet.Value; 
                xmlWriter.WriteStartElement(XmlConstants.EntitySet);
                xmlWriter.WriteAttributeString(XmlConstants.Name, entitySet.Key); 
                xmlWriter.WriteAttributeString(XmlConstants.EntityType, container.ResourceType.FullName); 

#if ASTORIA_CONTAINMENT 

                if (container.ContainmentCanonicalParent != null)
                {
                    xmlWriter.WriteAttributeString( 
                        XmlConstants.DataWebAccessTopLevelAccessAttribute,
                        XmlConstants.DataWebMetadataNamespace, 
                        XmlConvert.ToString(container.TopLevelAccess)); 
                }
 
#endif

                xmlWriter.WriteEndElement();
            } 

            this.WriteAssociationSets(xmlWriter, associations.Values); 
            this.WriteServiceOperations(xmlWriter, this.ServiceOperations); 
            xmlWriter.WriteEndElement();
        } 

        /// 
        /// Stores information about an end of an association.
        ///  
        private struct EndInfo
        { 
            /// Name of the relationship end  
            internal readonly string Name;
 
            /// Type of the relationship end.
            internal readonly ResourceType Type;

            /// Mulitplicity of the relationship end  
            internal readonly string Multiplicity;
 
            ///  
            /// Creates a new instance of EndInfo.
            ///  
            /// name of the end.
            /// resource type that the end refers to.
            /// multiplicity of the end.
            internal EndInfo(string name, ResourceType type, string multiplicity) 
            {
                this.Name = name; 
                this.Type = type; 
                this.Multiplicity = multiplicity;
            } 
        }

        /// 
        /// Stores information about a association and its ends 
        /// 
        private class AssociationInfo 
        { 
            /// FullName of the association.
            internal readonly string FullName; 

            /// Name of the association 
            internal readonly string Name;
 
            /// collection of ends for this association.
            internal readonly EndInfo[] Ends; 
 
            /// 
            /// Creates a new instance of AssociationInfo to store information about an association. 
            /// 
            /// name of the association.
            /// namespaceName of the association.
            /// first end of the association. 
            /// second end of the association.
            internal AssociationInfo(string name, string namespaceName, EndInfo end1, EndInfo end2) 
            { 
                this.Name = name;
                this.FullName = namespaceName + "." + name; 
                this.Ends = new EndInfo[] { end1, end2 };
            }
        }
 
        /// 
        /// Finds all the interesting types and their members given the top level type. 
        ///  
        private class TypeManager
        { 
            /// List of namespace along with the types in that namespace
            private Dictionary> namespaceManager = new Dictionary>(StringComparer.Ordinal);

            ///  
            /// Constructs a new instance of TypeManager using the knownTypes
            ///  
            /// list of known resource types 
            internal TypeManager(IEnumerable knownTypes)
            { 
                foreach (ResourceType resourceType in knownTypes)
                {
                    // Ignore Primitive types
                    if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive) 
                    {
                        continue; 
                    } 

                    List typesInSameNamespace; 
                    string typeNamespace = WebUtil.GetModelTypeNamespace(resourceType.Type);
                    if (!this.namespaceManager.TryGetValue(typeNamespace, out typesInSameNamespace))
                    {
                        typesInSameNamespace = new List(); 
                        this.namespaceManager.Add(typeNamespace, typesInSameNamespace);
                    } 
 
                    // Add the type to the list of types in the same namespace
                    typesInSameNamespace.Add(resourceType); 
                }
            }

            ///  
            /// Returns the list of namespace and the types in those namespaces
            ///  
            internal IEnumerable>> NamespaceAlongWithTypes 
            {
                get 
                {
                    return this.namespaceManager;
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides the interface definition for web data service
//      data sources. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Data.Services.Caching;
    using System.Data.Services.Common;
    using System.Diagnostics;
    using System.Linq; 
    using System.Reflection;
    using System.Xml; 
 
    #endregion Namespaces.
 
    /// 
    /// Provides a reflection-based IDataServiceProvider implementation.
    /// 
    [DebuggerDisplay("ReflectionServiceProvider: {Type}")] 
    internal class ReflectionServiceProvider : BaseServiceProvider
    { 
        ///  
        /// Initializes a new System.Data.Services.ReflectionServiceProvider instance.
        ///  
        /// Metadata for this provider.
        /// instance of the data source provider.
        internal ReflectionServiceProvider(MetadataCacheItem metadata, object dataSourceInstance)
            : base(metadata, dataSourceInstance) 
        {
        } 
 
        /// Gets a value indicating whether null propagation is required in expression trees.
        public override bool NullPropagationRequired 
        {
            get { return true; }
        }
 
        /// 
        /// Provides a name for the context in which all resource containers are. 
        ///  
        public override string ResourceContextName
        { 
            get
            {
                return XmlConvert.EncodeName(this.Type.Name);
            } 
        }
 
        /// Gets the name of the container that holds this resource type.This method is called for open types only 
        /// Resource to get container for.
        ///  
        /// The name of the container for the specified resource; null if it cannot
        /// be determined.
        /// 
        public override ResourceContainer GetContainerForResourceType(Type resourceType) 
        {
            Debug.Assert(resourceType != null, "resourceType != null"); 
            return InternalGetContainerForResourceType(resourceType, this.EntitySets.Values); 
        }
 
        /// 
        /// Gets the container corresponding to the given navigation property
        /// The declaring type container name refers to the entity set that the declaring type belongs to
        ///  
        /// name of the entity container that the declaring type belongs to
        /// declaring type 
        /// resource navigation property 
        /// name of the container that this property refers to
        public override ResourceContainer GetContainer(string declaringTypeContainerName, Type declaringResourceType, ResourceProperty resourceProperty) 
        {
            Debug.Assert(declaringTypeContainerName != null, "declaringTypeContainerName != null");
            Debug.Assert(declaringResourceType != null, "declaringResourceType != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 
            return InternalGetContainerForResourceType(resourceProperty.ResourceClrType, this.EntitySets.Values);
        } 
 
        /// Gets the metadata document for this provider.
        /// Writer to which metadata XML should be written. 
        public override void GetMetadata(XmlWriter xmlWriter)
        {
            Debug.Assert(xmlWriter != null, "xmlWriter != null");
            TypeManager typeManager = new TypeManager(this.Types); 
            BaseServiceProvider.WriteTopLevelSchemaElements(xmlWriter);
            Dictionary associations = new Dictionary(StringComparer.Ordinal); 
            List typesInEntityContainerNamespace = null; 

            // Write the schema Element for every namespace 
            foreach (KeyValuePair> namespaceAlongWithTypes in typeManager.NamespaceAlongWithTypes)
            {
                // If the types live in the same namespace as that of entity container and types that don't live in any namespace,
                // should be written out in the service namespace. If the service type also doesn't have a namespace, we will use 
                // the service name as the namespace. See code below for that.
                if (namespaceAlongWithTypes.Key == this.Type.Namespace  || String.IsNullOrEmpty(namespaceAlongWithTypes.Key)) 
                { 
                    // We can't write the entity container until we have figured out all the associations.
                    // Hence storing the type information for types which live in the same namespace as that 
                    // of entity container and writting them at the end along with the entity container.
                    if (typesInEntityContainerNamespace == null)
                    {
                        typesInEntityContainerNamespace = namespaceAlongWithTypes.Value; 
                    }
                    else 
                    { 
                        typesInEntityContainerNamespace.AddRange(namespaceAlongWithTypes.Value);
                    } 
                }
                else
                {
                    var associationsInThisNamespace = new Dictionary(StringComparer.Ordinal); 
                    BaseServiceProvider.WriteSchemaElement(xmlWriter, namespaceAlongWithTypes.Key, this.CompatibleWithV1Schema);
                    WriteTypes(xmlWriter, namespaceAlongWithTypes.Value, associations, associationsInThisNamespace); 
                    WriteAssociations(xmlWriter, associationsInThisNamespace.Values); 
                    xmlWriter.WriteEndElement();
                } 
            }

            // Write the entity container definition. Also if there are types in the same namespace,
            // we need to write them out too. 
            string typeNamespace = this.Type.Namespace;
            if (String.IsNullOrEmpty(typeNamespace)) 
            { 
                typeNamespace = XmlConvert.EncodeName(this.Type.Name);
            } 

            BaseServiceProvider.WriteSchemaElement(xmlWriter, typeNamespace, this.CompatibleWithV1Schema);
            if (typesInEntityContainerNamespace != null)
            { 
                var associationsInThisNamespace = new Dictionary(StringComparer.Ordinal);
                WriteTypes(xmlWriter, typesInEntityContainerNamespace, associations, associationsInThisNamespace); 
                WriteAssociations(xmlWriter, associationsInThisNamespace.Values); 
            }
 
            this.WriteEntityContainer(xmlWriter, this.ResourceContextName, this.EntitySets, associations);
            xmlWriter.WriteEndElement();

            // These end elements balance the elements written out in WriteTopLevelSchemaElements 
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement(); 
            xmlWriter.Flush(); 
        }
 
        /// 
        /// Get the list of etag property names given the entity set name and the instance of the resource
        /// 
        /// name of the entity set 
        /// clr type of the resource whose etag properties need to be fetched
        /// list of etag property names 
        public override ICollection GetETagProperties(string containerName, Type resourceClrType) 
        {
            Debug.Assert(resourceClrType != null, "clrType cannot be null"); 
            ResourceType resourceType = ((IDataServiceProvider)this).GetResourceType(resourceClrType);
            Debug.Assert(resourceType != null, "resourceType != null");

            return resourceType.ETagProperties; 
        }
 
        ///  
        /// Checks whether the specified  is ordered.
        ///  
        /// Type to check.
        /// true if the type may be ordered; false otherwise.
        /// 
        /// The ordering may still fail at runtime; this method is currently 
        /// used for cleaner error messages only.
        ///  
        public override bool GetTypeIsOrdered(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 
            if (typeof(IComparable).IsAssignableFrom(type))
            {
                return true;
            } 
            else
            { 
                return base.GetTypeIsOrdered(type); 
            }
        } 

        #region IUpdatable Members

        ///  
        /// Creates the resource of the given type and belonging to the given container
        ///  
        /// container name to which the resource needs to be added 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and belonging to the given container 
        public override object CreateResource(string containerName, string fullTypeName)
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            { 
                object resource = ((IUpdatable)this.CurrentDataSource).CreateResource(containerName, fullTypeName);
                if (resource == null) 
                { 
                    throw new InvalidOperationException(Strings.BadProvider_CreateResourceReturnedNull);
                } 

                return resource;
            }
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            } 
        }
 
        /// 
        /// Gets the resource of the given type that the query points to
        /// 
        /// query pointing to a particular resource 
        /// full type name i.e. Namespace qualified type name of the resource
        /// object representing a resource of given type and as referenced by the query 
        public override object GetResource(IQueryable query, string fullTypeName) 
        {
            object resource = null; 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                try
                { 
                    resource = ((IUpdatable)this.CurrentDataSource).GetResource(query, fullTypeName);
                } 
                catch (ArgumentException e) 
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidUriSpecified, e); 
                }
            }
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
 
            return resource;
        } 

        /// 
        /// Resets the value of the given resource to its default value
        ///  
        /// resource whose value needs to be reset
        /// same resource with its value reset 
        public override object ResetResource(object resource) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            {
                resource = ((IUpdatable)this.CurrentDataSource).ResetResource(resource);
            }
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            } 

            return resource; 
        }

        /// 
        /// Sets the value of the given property on the target object 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// value of the property
        public override void SetValue(object targetResource, string propertyName, object propertyValue) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).SetValue(targetResource, propertyName, propertyValue); 
            }
            else 
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
        }

        /// 
        /// Gets the value of the given property on the target object 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// the value of the property for the given target resource
        public override object GetValue(object targetResource, string propertyName) 
        {
            object resource = null;
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            { 
                resource = ((IUpdatable)this.CurrentDataSource).GetValue(targetResource, propertyName);
            } 
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }

            if (resource == null)
            { 
                throw DataServiceException.CreateResourceNotFound(propertyName);
            } 
 
            return resource;
        } 

        /// 
        /// Sets the value of the given reference property on the target object
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property 
        public override void SetReference(object targetResource, string propertyName, object propertyValue)
        { 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).SetReference(targetResource, propertyName, propertyValue);
            } 
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }
        } 

        /// 
        /// Adds the given value to the collection
        ///  
        /// target object which defines the property
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be added 
        public override void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
        { 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).AddReferenceToCollection(targetResource, propertyName, resourceToBeAdded);
            } 
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }
        } 

        /// Applies expansions to the specified .
        ///  object to expand.
        /// A collection of ordered  paths. 
        /// 
        /// An  object of the same type as the given , 
        /// with the results including the specified . 
        /// 
        ///  
        /// This method may modify the  to indicate which expansions
        /// are included.
        ///
        /// The returned  may implement the  
        /// interface to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects. 
        ///  
        public override IEnumerable ApplyExpansions(IQueryable queryable, ICollection expandPaths)
        { 
            IExpandProvider provider = this.CurrentDataSource as IExpandProvider;
            if (provider != null)
            {
                return provider.ApplyExpansions(queryable, expandPaths); 
            }
            else 
            { 
                foreach (ExpandSegmentCollection path in expandPaths)
                { 
                    if (path.HasFilter)
                    {
                        return new BasicExpandProvider(this, true).ApplyExpansions(queryable, expandPaths);
                    } 
                }
 
                // This pass-through implementation is appropriate for providers that fault-in on demand. 
                return queryable;
            } 
        }

        /// 
        /// Removes the given value from the collection 
        /// 
        /// target object which defines the property 
        /// name of the property whose value needs to be updated 
        /// value of the property which needs to be removed
        public override void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).RemoveReferenceFromCollection(targetResource, propertyName, resourceToBeRemoved); 
            }
            else 
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
        }

        /// 
        /// Delete the given resource 
        /// 
        /// resource that needs to be deleted 
        public override void DeleteResource(object targetResource) 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            {
                ((IUpdatable)this.CurrentDataSource).DeleteResource(targetResource);
            }
            else 
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            } 
        }
 
        /// 
        /// Saves all the pending changes made till now
        /// 
        public override void SaveChanges() 
        {
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            { 
                ((IUpdatable)this.CurrentDataSource).SaveChanges();
            } 
            else
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 
        }
 
        ///  
        /// Returns the actual instance of the resource represented by the given resource object
        ///  
        /// object representing the resource whose instance needs to be fetched
        /// The actual instance of the resource represented by the given resource object
        public override object ResolveResource(object resource)
        { 
            object resolvedResource = null;
            if (typeof(IUpdatable).IsAssignableFrom(this.Type)) 
            { 
                resolvedResource = ((IUpdatable)this.CurrentDataSource).ResolveResource(resource);
            } 
            else
            {
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates);
            } 

            if (resolvedResource == null) 
            { 
                throw new InvalidOperationException(Strings.BadProvider_ResolveResourceReturnedNull);
            } 

            return resolvedResource;
        }
 
        /// 
        /// Revert all the pending changes. 
        ///  
        public override void ClearChanges()
        { 
            if (typeof(IUpdatable).IsAssignableFrom(this.Type))
            {
                ((IUpdatable)this.CurrentDataSource).ClearChanges();
            } 
            else
            { 
                throw DataServiceException.CreateMethodNotImplemented(Strings.DataSourceMustImplementIUpdatableToSupportUpdates); 
            }
        } 

        #endregion

        /// Checks whether the given property is a key property. 
        /// property to check
        /// returns the key kind of the property, based on the heuristic it matches 
        /// true if this is a key property, else returns false 
        internal static bool IsPropertyKeyProperty(PropertyInfo property, out ResourceKeyKind keyKind)
        { 
            keyKind = (ResourceKeyKind)(-1);

            // Only primitive types are allowed to be keys.
            // Checks for generic to exclude Nullable<> value-type primitives, since we don't allows keys to be null. 
            if (WebUtil.IsPrimitiveType(property.PropertyType) &&
                !property.PropertyType.IsGenericType) 
            { 
                DataServiceKeyAttribute keyAttribute = property.ReflectedType.GetCustomAttributes(true).OfType().FirstOrDefault();
                if (keyAttribute != null && keyAttribute.KeyNames.Contains(property.Name)) 
                {
                    keyKind = ResourceKeyKind.AttributedKey;
                    return true;
                } 

                // For now, the key property must be {TypeName}Id or Id and the property 
                // type must be primitive, since we do not support non-primitive types 
                // as keys
                if (property.Name == property.DeclaringType.Name + "ID") 
                {
                    keyKind = ResourceKeyKind.TypeNameId;
                    return true;
                } 
                else if (property.Name == "ID")
                { 
                    keyKind = ResourceKeyKind.Id; 
                    return true;
                } 
            }

            return false;
        } 

#if ASTORIA_CONTAINMENT 
 
        /// 
        /// Returns an object that can enumerate all  
        /// instances that apply to this model.
        /// 
        /// 
        /// An object that can enumerate all  
        /// instances that apply to this model.
        ///  
        protected override IEnumerable EnumerateAccessPathAttributes() 
        {
            Type provider = this.Type; 
            foreach (ResourceContainer container in this.EntitySets.Values)
            {
                PropertyInfo property = provider.GetProperty(container.Name, WebUtil.PublicInstanceBindingFlags);
                Debug.Assert(property != null, "property != null -- otherwise " + container.Name + " shouldn't be in metadata."); 
                object[] attributes = property.GetCustomAttributes(true);
                if (attributes == null || attributes.Length == 0) 
                { 
                    continue;
                } 

                foreach (AccessPathAttribute attribute in attributes.OfType())
                {
                    attribute.AnnotatedContainer = container; 
                    yield return attribute;
                } 
            } 
        }
 
#endif

        /// Populates the metadata for this provider.
        ///  
        /// Dictionary of known CLR to ResourceType entries, which is
        /// populated as metadata is built. 
        ///  
        /// 
        /// Dictionary of name to ResourceContainer for entity sets, populated 
        /// as metadata is built.
        /// 
        protected override void PopulateMetadata(
            IDictionary knownTypes, IDictionary entitySets) 
        {
            Queue unvisitedTypes = new Queue(); 
 
            // Get the list of properties to be ignored.
            List propertiesToBeIgnored = new List( 
                IgnorePropertiesAttribute.GetProperties(this.Type, true /*inherit*/, WebUtil.PublicInstanceBindingFlags));
            PropertyInfo[] properties = this.Type.GetProperties(WebUtil.PublicInstanceBindingFlags);
            foreach (PropertyInfo property in properties)
            { 
                if (!propertiesToBeIgnored.Contains(property.Name) && property.CanRead && property.GetIndexParameters().Length == 0)
                { 
                    Type elementType = BaseServiceProvider.GetIQueryableElement(property.PropertyType); 
                    if (elementType != null)
                    { 
                        // If the element type has key defined (in itself or one of its ancestors)
                        ResourceType resourceType = BuildHierarchyForEntityType(elementType, knownTypes, unvisitedTypes, true /* entity type candidate */);
                        if (resourceType != null)
                        { 
                            // We do not allow MEST scenaria for reflection provider
                            foreach (KeyValuePair entitySetInfo in entitySets) 
                            { 
                                Type entitySetType = entitySetInfo.Value.ElementType;
                                if (entitySetType.IsAssignableFrom(elementType)) 
                                {
                                    throw new InvalidOperationException(Strings.ReflectionProvider_MultipleEntitySetsForSameType(entitySetInfo.Value.Name, property.Name, entitySetType.FullName, resourceType.FullName));
                                }
                                else if (elementType.IsAssignableFrom(entitySetType)) 
                                {
                                    throw new InvalidOperationException(Strings.ReflectionProvider_MultipleEntitySetsForSameType(property.Name, entitySetInfo.Value.Name, resourceType.FullName, entitySetType.FullName)); 
                                } 
                            }
 
                            // Add the entity set to the list of entity sets.
                            ResourceContainer resourceContainer = new ResourceContainer(property.Name, resourceType);
                            entitySets.Add(property.Name, resourceContainer);
                        } 
                        else
                        { 
                            throw new InvalidOperationException(Strings.ReflectionProvider_InvalidEntitySetProperty(property.Name, this.ResourceContextName)); 
                        }
                    } 
                }
            }

            // Populate the metadata for all the types in unvisited types 
            // and also their properties and populates metadata about property types
            PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets.Values); 
 
            // At this point, we should have all the top level entity types and the complex types
            PopulateMetadataForDerivedTypes(knownTypes, unvisitedTypes, entitySets.Values); 
        }

        /// 
        /// Creates the IQueryable instance for the given resource container and returns it 
        /// 
        /// resource container for which IQueryable instance needs to be created 
        /// returns the IQueryable instance for the given resource container 
        protected override IQueryable GetResourceContainerInstance(ResourceContainer resourceContainer)
        { 
            Debug.Assert(resourceContainer != null, "resourceContainer != null");
            if (resourceContainer.ReadFromContextDelegate == null)
            {
                PropertyInfo propertyInfo = this.Type.GetProperty(resourceContainer.Name, WebUtil.PublicInstanceBindingFlags); 
                MethodInfo getValueMethod = propertyInfo.GetGetMethod();
 
                // return ((TheContext)arg0).get_Property(); 
                Type[] parameterTypes = new Type[] { typeof(object) };
                System.Reflection.Emit.DynamicMethod readerMethod = new System.Reflection.Emit.DynamicMethod("queryable_reader", typeof(IQueryable), parameterTypes, false); 
                var generator = readerMethod.GetILGenerator();
                generator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
                generator.Emit(System.Reflection.Emit.OpCodes.Castclass, this.Type);
                generator.Emit(System.Reflection.Emit.OpCodes.Call, getValueMethod); 
                generator.Emit(System.Reflection.Emit.OpCodes.Ret);
                resourceContainer.ReadFromContextDelegate = (Func)readerMethod.CreateDelegate(typeof(Func)); 
            } 

            Debug.Assert(resourceContainer.ReadFromContextDelegate != null, "resourceContainer.ReadFromContextDelegate != null"); 
            return resourceContainer.ReadFromContextDelegate(this.CurrentDataSource);
        }

        ///  
        /// Populate types for metadata specified by the provider
        ///  
        /// list of types specified by the provider 
        /// list of already known types
        /// list of entity sets as specified in the data source type 
        protected override void PopulateMetadataForUserSpecifiedTypes(
            IEnumerable userSpecifiedTypes, IDictionary knownTypes, IEnumerable entitySets)
        {
            Queue unvisitedTypes = new Queue(); 
            foreach (Type type in userSpecifiedTypes)
            { 
                ResourceType resourceType; 
                if (knownTypes.TryGetValue(type, out resourceType))
                { 
                    continue;
                }

                if (IsEntityOrComplexType(type, knownTypes, unvisitedTypes) == null) 
                {
                    throw new InvalidOperationException(Strings.BadProvider_InvalidTypeSpecified(type.FullName)); 
                } 
            }
 
            PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets);
        }

        ///  
        /// Populate metadata for the given clr type.
        ///  
        /// type whose metadata needs to be loaded. 
        /// list of already known resource types.
        /// list of entity sets as specified in the data source. 
        /// resource type containing metadata for the given clr type.
        protected override ResourceType PopulateMetadataForType(Type type, IDictionary knownTypes, IEnumerable entitySets)
        {
            Queue unvisitedTypes = new Queue(); 
            ResourceType resourceType;
            if (!knownTypes.TryGetValue(type, out resourceType)) 
            { 
                resourceType = IsEntityOrComplexType(type, knownTypes, unvisitedTypes);
                if (resourceType != null) 
                {
                    PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets);
                }
            } 

            return resourceType; 
        } 

        /// Checks whether the specified type is a complex type. 
        /// Type to check.
        /// 
        /// true if the specified type is a complex type; false otherwise. Note
        /// that resources are not distinguished from complex types. 
        /// 
        private static bool IsComplexType(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
 
            // Complex types are all types that contain public properties of primitive
            // types.
            //
            // We purposefully ignore certain known classes which fit this description 
            // but we know are not meaningful for Astoria:
            // - System.Array:  what would get serialized would be Length, IsFixed, etc. 
            // - Pointers:      we would otherwise serialize the pointer size 
            // - COM object wrappers
            // - interface: since we will never know what the exact type of the instance will be. 
            if (!type.IsVisible || type.IsArray || type.IsPointer || type.IsCOMObject || type.IsInterface ||
                type == typeof(IntPtr) || type == typeof(UIntPtr) || type == typeof(char) ||
                type == typeof(TimeSpan) || type == typeof(DateTimeOffset) || type == typeof(Uri) ||
                type.IsEnum) 
            {
                return false; 
            } 

            // For nullable types, we care whether the underlying value type is 
            // complex type.
            Type nullableUnderlyingType = Nullable.GetUnderlyingType(type);
            if (nullableUnderlyingType != null)
            { 
                return ReflectionServiceProvider.IsComplexType(nullableUnderlyingType);
            } 
 
            return true;
        } 

        /// 
        /// Checks whether there is a key defined for the given type.
        ///  
        /// type to check 
        ///  
        /// Whether  is being considered as a possible 
        /// entity type.
        ///  
        /// returns true if there are one or key properties present else returns false
        private static bool DoesTypeHaveKeyProperties(Type type, bool entityTypeCandidate)
        {
            Debug.Assert(type != null, "type != null"); 

            // Check for properties declared on this element only 
            foreach (PropertyInfo property in type.GetProperties(WebUtil.PublicInstanceBindingFlags | BindingFlags.DeclaredOnly)) 
            {
                ResourceKeyKind keyKind; 
                if (IsPropertyKeyProperty(property, out keyKind))
                {
                    if (keyKind == ResourceKeyKind.AttributedKey && !entityTypeCandidate)
                    { 
                        throw new InvalidOperationException(Strings.ReflectionProvider_EntityTypeHasKeyButNoEntitySet(type.FullName));
                    } 
 
                    if (!entityTypeCandidate)
                    { 
                        return false;
                    }

                    return true; 
                }
            } 
 
            return false;
        } 

        /// 
        /// Populates the metadata for the given unvisited types and all the associated types with this type
        ///  
        /// list of known types
        /// list of unvisited type 
        /// Available entity sets. 
        private static void PopulateMetadataForTypes(
            IDictionary knownTypes, 
            Queue unvisitedTypes,
            IEnumerable entitySets)
        {
            Debug.Assert(knownTypes != null, "knownTypes != null"); 
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null"); 
 
            // Start walking down all the types
            while (unvisitedTypes.Count != 0) 
            {
                // get the unvisited element
                ResourceType type = unvisitedTypes.Dequeue();
 
                // Go through all the properties and find out one or more complex types
                BuildTypeProperties(type, knownTypes, unvisitedTypes, entitySets); 
            } 
        }
 
        /// 
        /// Walks through the list of ancestors and finds the root base type and collects metadata for the entire chain of ancestors
        /// 
        /// type whose ancestors metadata needs to be populated 
        /// list of already known types
        /// list of unvisited types 
        /// Whether  is a candidate to be an entity type. 
        /// return true if this given type is a entity type, otherwise returns false
        private static ResourceType BuildHierarchyForEntityType( 
            Type type, IDictionary knownTypes, Queue unvisitedTypes, bool entityTypeCandidate)
        {
            List ancestors = new List();
 
            if (!type.IsVisible)
            { 
                return null; 
            }
 
            Type baseType = type;
            ResourceType baseResourceType = null;

            // Since this method is also used on property types, which can be interfaces, 
            // Base types can be null
            while (baseType != null) 
            { 
                // Try and check if the base type is already loaded
                if (knownTypes.TryGetValue(baseType, out baseResourceType)) 
                {
                    break;
                }
 
                ancestors.Add(baseType);
                baseType = baseType.BaseType; 
            } 

            if (baseResourceType == null) 
            {
                // If entityTypeCandidate is false, then it means that the current type can't
                // be a entity type with keys. In other words, it must derive from an existing
                // type. Otherwise, its not an entity type 
                if (entityTypeCandidate == false)
                { 
                    return null; 
                }
 
                // Find the last ancestor which has key defined
                for (int i = ancestors.Count - 1; i >= 0; i--)
                {
                    if (DoesTypeHaveKeyProperties(ancestors[i], entityTypeCandidate)) 
                    {
                        break; 
                    } 

                    // Else this type is not interesting. Remove it from the ancestors list 
                    ancestors.RemoveAt(i);
                }
            }
            else if (baseResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) 
            {
                return null; 
            } 
            else if (ancestors.Count == 0)
            { 
                // we might have found the top level element.So just return
                return baseResourceType;
            }
 
            // For all the valid ancestors, add the type to the list of types encountered
            // and unvisited types 
            // its important that we enqueue the ancestors first, since when we populate member metadata 
            // we can make sure that the base type is fully populated
            for (int i = ancestors.Count - 1; i >= 0; i--) 
            {
                ResourceType entityType = new ResourceType(ancestors[i], ResourceTypeKind.EntityType, baseResourceType);
                unvisitedTypes.Enqueue(entityType);
                knownTypes.Add(ancestors[i], entityType); 
                baseResourceType = entityType;
            } 
 
            return baseResourceType;
        } 

        /// 
        /// Populates the metadata for the properties of the given resource type
        ///  
        /// resource type whose properties metadata needs to be populated
        /// list of known types 
        /// list of unvisited type 
        /// Available entity sets.
        private static void BuildTypeProperties( 
            ResourceType parentResourceType,
            IDictionary knownTypes,
            Queue unvisitedTypes,
            IEnumerable 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 propertiesToBeIgnored = new HashSet(StringComparer.Ordinal);
#if ASTORIA_OPEN_OBJECT
            if (parentResourceType.IsOpenType)
            { 
                propertiesToBeIgnored.Add(OpenTypeAttribute.GetOpenPropertyName(parentResourceType.Type));
            } 
#endif 

            foreach (string propertyName in IgnorePropertiesAttribute.GetProperties(parentResourceType.Type, false /*inherit*/, bindingFlags)) 
            {
                propertiesToBeIgnored.Add(propertyName);
            }
 
            ResourceKeyKind keyKind = (ResourceKeyKind)Int32.MaxValue;
            PropertyInfo[] properties = parentResourceType.Type.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 = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
                    ResourceContainer container = null;
                    bool collection = false; 

                    if (!knownTypes.TryGetValue(resourcePropertyType, out resourceType)) 
                    { 
                        Type collectionType = GetIEnumerableElement(property.PropertyType);
                        if (collectionType != null) 
                        {
                            knownTypes.TryGetValue(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 != null)
                                    { 
                                        // 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, 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) 
                        {
                            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);
                        Debug.Assert(container != null, "container != null");
                    } 

                    ResourceProperty resourceProperty = new ResourceProperty(property, kind, MimeTypeAttribute.GetMemberMimeType(property), resourceType, container); 
                    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)); 
            }

            parentResourceType.SortKeyMembers();
            LoadETagProperties(parentResourceType); 
        }
 
        ///  
        /// If the given type is a entity or complex type, it returns the resource type corresponding to the given type
        ///  
        /// clr type
        /// list of already known types
        /// list of unvisited types
        /// resource type corresponding to the given clr type, if the clr type is entity or complex 
        private static ResourceType IsEntityOrComplexType(Type type, IDictionary knownTypes, Queue unvisitedTypes)
        { 
            // Ignore values types here. We do not support resources of values type (entity or complex) 
            if (type.IsValueType)
            { 
                return null;
            }

            ResourceType resourceType = BuildHierarchyForEntityType(type, knownTypes, unvisitedTypes, false /* entityTypeCandidate */); 
            if (resourceType == null && IsComplexType(type))
            { 
                resourceType = new ResourceType(type, ResourceTypeKind.ComplexType); 
                knownTypes.Add(type, resourceType);
                unvisitedTypes.Enqueue(resourceType); 
            }

            return resourceType;
        } 

        /// Get the resource container for the given clr type. 
        /// clr type for which resource container name needs to be returned 
        /// Available entity sets to consider.
        /// The container for its type, null if not found. 
        private static ResourceContainer InternalGetContainerForResourceType(Type type, IEnumerable entitySets)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(entitySets != null, "entitySets != null"); 

            // For each entity set, find out which one matches the type of this resource 
            foreach (ResourceContainer entitySetInfo in entitySets) 
            {
                if (entitySetInfo.ElementType.IsAssignableFrom(type)) 
                {
                    return entitySetInfo;
                }
            } 

            return null; 
        } 

        ///  
        /// Find out all the derived types in the list of assemblies and then populate metadata for those types
        /// 
        /// list of known types
        /// list of unvisited types 
        /// Available entity sets.
        private static void PopulateMetadataForDerivedTypes( 
            IDictionary knownTypes, Queue unvisitedTypes, IEnumerable entitySets) 
        {
            Debug.Assert(knownTypes != null, "knownTypes != null"); 
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");
            Debug.Assert(entitySets != null, "entitySets != null");

            // Find all the root resource entity types 
            List rootTypes = new List();
            foreach (ResourceType resourceType in knownTypes.Values) 
            { 
                if (resourceType.BaseType == null &&
                    resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) 
                {
                    rootTypes.Add(resourceType);
                }
            } 

            // Use the default comparer, which calls Assembly.Equals (not a simple reference comparison). 
            HashSet assemblies = new HashSet(EqualityComparer.Default); 
            List derivedTypes = new List();
 
            // Walk through all the types in the assemblies and find all the derived types
            foreach (ResourceType resourceType in knownTypes.Values)
            {
                // No need to look into primitive types, as these live in system assemblies. 
                if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                { 
                    continue; 
                }
 
                Assembly assembly = resourceType.Type.Assembly;
                //// ignore if the assembly has already been scanned
                if (assemblies.Contains(assembly))
                { 
                    continue;
                } 
 
                // Walk all the types in that assembly
                foreach (Type type in assembly.GetTypes()) 
                {
                    // skip all the non visible types
                    if (!type.IsVisible)
                    { 
                        continue;
                    } 
 
                    // Skip the type if its already loaded
                    if (knownTypes.ContainsKey(type)) 
                    {
                        continue;
                    }
 
                    // Check if this type dervies from any one of the root types
                    for (int i = 0; i < rootTypes.Count; i++) 
                    { 
                        if (rootTypes[i].Type.IsAssignableFrom(type))
                        { 
                            derivedTypes.Add(type);
                        }
                    }
                } 

                assemblies.Add(assembly); 
            } 

            foreach (Type type in derivedTypes) 
            {
                BuildHierarchyForEntityType(type, knownTypes, unvisitedTypes, false /* entityTypeCandidate */);
                PopulateMetadataForTypes(knownTypes, unvisitedTypes, entitySets);
            } 
        }
 
        ///  
        /// Write the facets for clr types
        ///  
        /// XmlWriter in which facets needs to be written
        /// property which contains the primitive type for which facets needs to be written
        private static void WritePrimitivePropertyFacets(XmlWriter xmlWriter, ResourceProperty resourceProperty)
        { 
            Debug.Assert(
                resourceProperty.IsOfKind(ResourcePropertyKind.Primitive), 
                "property must be of primitive type"); 

            bool nullable = true; 
            Type propertyType = resourceProperty.Type;

            // Key properties can't be nullable and can't be generic
            if (!resourceProperty.IsOfKind(ResourcePropertyKind.Key)) 
            {
                if (propertyType.IsGenericType && 
                    resourceProperty.Type.GetGenericTypeDefinition() == typeof(Nullable<>)) 
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType); 
                }
                else if (propertyType.IsValueType)
                {
                    nullable = false; 
                }
            } 
            else 
            {
                nullable = false; 
            }

            xmlWriter.WriteAttributeString(XmlConstants.Nullable, nullable ? XmlConstants.XmlTrueLiteral : XmlConstants.XmlFalseLiteral);
        } 

        ///  
        /// Write the metadata for the entityType in the xmlWriter 
        /// 
        /// xmlWriter in which metadata needs to be written 
        /// entityType whose metadata needs to be written
        /// list of associations present in the model.
        /// list of associations in the current namespace.
        private static void WriteEntityType( 
            XmlWriter xmlWriter,
            ResourceType entityType, 
            Dictionary associations, 
            Dictionary associationsInThisNamespace)
        { 
            Debug.Assert(xmlWriter != null, "XmlWriter cannot be null");
            Debug.Assert(entityType.ResourceTypeKind == ResourceTypeKind.EntityType, "Type must be entityType");

            xmlWriter.WriteStartElement(XmlConstants.EntityType); 
            xmlWriter.WriteAttributeString(XmlConstants.Name, XmlConvert.EncodeName(entityType.Name));
 
            if (entityType.Type.IsAbstract) 
            {
                xmlWriter.WriteAttributeString(XmlConstants.Abstract, "true"); 
            }

#if ASTORIA_OPEN_OBJECT
            if (entityType.IsOpenType && OpenTypeAttribute.DeclaresOpenType(entityType.Type)) 
            {
                xmlWriter.WriteAttributeString( 
                    XmlConstants.DataWebOpenTypeAttributeName, 
                    XmlConstants.DataWebNamespace,
                    OpenTypeAttribute.GetOpenPropertyName(entityType.Type)); 
            }
#endif

            if (entityType.BaseType != null) 
            {
                xmlWriter.WriteAttributeString(XmlConstants.BaseType, XmlConvert.EncodeName(entityType.BaseType.FullName)); 
            } 
            else
            { 
                xmlWriter.WriteStartElement(XmlConstants.Key);
                foreach (ResourceProperty property in entityType.KeyProperties)
                {
                    xmlWriter.WriteStartElement(XmlConstants.PropertyRef); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, property.Name);
                    xmlWriter.WriteEndElement(); 
                } 

                xmlWriter.WriteEndElement(); 
            }

            WriteProperties(xmlWriter, entityType, associations, associationsInThisNamespace);
            xmlWriter.WriteEndElement(); 
        }
 
        ///  
        /// Write the metadata for the complexType in the xmlWriter
        ///  
        /// xmlWriter in which metadata needs to be written
        /// complexType whose metadata needs to be written
        private static void WriteComplexType(XmlWriter xmlWriter, ResourceType complexType)
        { 
            Debug.Assert(xmlWriter != null, "XmlWriter cannot be null");
            Debug.Assert(complexType.ResourceTypeKind == ResourceTypeKind.ComplexType, "Type must be complexType"); 
 
            xmlWriter.WriteStartElement(XmlConstants.ComplexType);
            xmlWriter.WriteAttributeString(XmlConstants.Name, XmlConvert.EncodeName(complexType.Name)); 
            WriteProperties(xmlWriter, complexType, null, null);
            xmlWriter.WriteEndElement();
        }
 
        /// 
        /// Write the metadata of all the properties for the given typein the xmlWriter 
        ///  
        /// xmlWriter in which metadata needs to be written
        /// resource type whose property metadata needs to be written 
        /// list of associations present in the model.
        /// list of associations in the current namespace.
        private static void WriteProperties(
            XmlWriter xmlWriter, 
            ResourceType type,
            Dictionary associations, 
            Dictionary associationsInThisNamespace) 
        {
            Debug.Assert(xmlWriter != null, "xmlWriter != null"); 
            Debug.Assert(type != null, "type != null");
            for (int i = 0; i < type.PropertiesDeclaredInThisType.Count; i++)
            {
                ResourceProperty resourceProperty = type.PropertiesDeclaredInThisType[i]; 
                string elementName;
 
                // For primitive types, get the corresponding edm typename 
                if (resourceProperty.TypeKind == ResourceTypeKind.Primitive)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.Property);
                    xmlWriter.WriteAttributeString(XmlConstants.Name, resourceProperty.Name);
                    elementName = WebUtil.GetEdmTypeName(resourceProperty.Type);
                    xmlWriter.WriteAttributeString(XmlConstants.Type, elementName); 
                    WritePrimitivePropertyFacets(xmlWriter, resourceProperty);
                    if (!String.IsNullOrEmpty(resourceProperty.MimeType)) 
                    { 
                        BaseServiceProvider.WriteDataWebMetadata(xmlWriter, XmlConstants.DataWebMimeTypeAttributeName, resourceProperty.MimeType);
                    } 

                    if (type.ResourceTypeKind == ResourceTypeKind.EntityType &&
                        type.ETagProperties.Contains(resourceProperty))
                    { 
                        xmlWriter.WriteAttributeString(XmlConstants.ConcurrencyAttribute, XmlConstants.ConcurrencyFixedValue);
                    } 
                } 
                else if (resourceProperty.Kind == ResourcePropertyKind.ComplexType)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.Property);
                    xmlWriter.WriteAttributeString(XmlConstants.Name, resourceProperty.Name);
                    elementName = resourceProperty.ResourceType.FullName;
                    xmlWriter.WriteAttributeString(XmlConstants.Type, elementName); 

                    // Edm doesn't support nullable complex type properties 
                    xmlWriter.WriteAttributeString(XmlConstants.Nullable, XmlConstants.XmlFalseLiteral); 
                }
                else 
                {
                    Debug.Assert(
                        ResourceTypeKind.EntityType == resourceProperty.TypeKind,
                        "Unexpected property type kind"); 
                    bool multivalued = false;
 
                    xmlWriter.WriteStartElement(XmlConstants.NavigationProperty); 
                    xmlWriter.WriteAttributeString(XmlConstants.Name, resourceProperty.Name);
                    elementName = resourceProperty.ResourceType.FullName; 
                    if (resourceProperty.Kind == ResourcePropertyKind.ResourceSetReference)
                    {
                        multivalued = true;
                    } 

                    // for every nav property, add a new association to the metadata 
                    // the name of the assocation will be _ 
                    // there might be conflicts since there can be 2 types with the same name, but in different namespace.
                    // in that case, we will use the full type name (replace '.' by '_'). That should make it unique. 
                    string associationName = type.Name + '_' + resourceProperty.Name;
                    if (associations.ContainsKey(associationName))
                    {
                        associationName = type.FullName.Replace('.', '_') + '_' + resourceProperty.Name; 
                    }
 
                    AssociationInfo association = new AssociationInfo( 
                        associationName,
                        type.Type.Namespace, 
                        new EndInfo(resourceProperty.Name, resourceProperty.ResourceType, multivalued ? XmlConstants.Many : XmlConstants.ZeroOrOne),
                        new EndInfo(type.Name, type, XmlConstants.Many));

                    // Add it to both the global list and the current namespace list. 
                    associationsInThisNamespace.Add(associationName, association);
                    associations.Add(associationName, association); 
 
                    xmlWriter.WriteAttributeString(XmlConstants.Relationship, association.FullName);
                    xmlWriter.WriteAttributeString(XmlConstants.FromRole, type.Name); 
                    xmlWriter.WriteAttributeString(XmlConstants.ToRole, resourceProperty.Name);

#if ASTORIA_CONTAINMENT
 
                    if (resourceProperty.ContainmentTarget != null)
                    { 
                        string path = resourceProperty.ContainmentTargetCanonical ? 
                            XmlConstants.DataWebAccessPathCanonicalValue :
                            XmlConstants.DataWebAccessPathNonCanonicalValue; 
                        BaseServiceProvider.WriteDataWebMetadata(xmlWriter, XmlConstants.DataWebAccessPathAttribute, path);
                        BaseServiceProvider.WriteDataWebMetadata(
                            xmlWriter, XmlConstants.DataWebAccessPathTargetAttribute, resourceProperty.ContainmentTarget.Name);
                        BaseServiceProvider.WriteDataWebMetadata( 
                            xmlWriter, XmlConstants.DataWebAccessPathChildKeysAttribute, string.Join(",", resourceProperty.ContainmentChildKeys));
                        BaseServiceProvider.WriteDataWebMetadata( 
                            xmlWriter, XmlConstants.DataWebAccessPathParentKeysAttribute, string.Join(",", resourceProperty.ContainmentParentKeys)); 
                    }
 
#endif
                }

                xmlWriter.WriteEndElement(); 
            }
        } 
 
        /// 
        /// Writes the definition of types in the XmlWriter 
        /// 
        /// xmlWriter in which metadata needs to be written
        /// resourceTypes whose metadata needs to be written
        /// list of associations present in the model. 
        /// list of associations in the current namespace.
        private static void WriteTypes( 
            XmlWriter xmlWriter, 
            List types,
            Dictionary associations, 
            Dictionary associationsInThisNamespace)
        {
            foreach (ResourceType type in types)
            { 
                if (ResourceTypeKind.EntityType == type.ResourceTypeKind)
                { 
                    WriteEntityType(xmlWriter, type, associations, associationsInThisNamespace); 
                }
                else 
                {
                    Debug.Assert(ResourceTypeKind.ComplexType == type.ResourceTypeKind, "this must be a complex type");
                    WriteComplexType(xmlWriter, type);
                } 
            }
        } 
 
        /// 
        /// Loads the etag properties for the given resource type 
        /// 
        /// resource type whose etag property names need to be loaded.
        private static void LoadETagProperties(ResourceType resourceType)
        { 
            // if it is the root type, then we need to inherit the attribute from the base type.
            // otherwise, we need not, since if the base type already has it, the appropriate properties 
            // must already have been marked as concurrency properties. 
            bool inherit = resourceType.BaseType == null;
 
            // Read the etag attribute from the type and return it
            ETagAttribute[] attributes = (ETagAttribute[])resourceType.Type.GetCustomAttributes(typeof(ETagAttribute), inherit);
            Debug.Assert(attributes.Length <= 1, "Only one attribute can be specified per type");
 
            if (attributes.Length == 1)
            { 
                // Validate the property names 
                // we may need to cache them instead of reading them everytime
                foreach (string propertyName in attributes[0].PropertyNames) 
                {
                    ResourceProperty property = resourceType.TryResolvePropertyNameDefinedInThisType(propertyName);
                    if (property == null)
                    { 
                        throw new InvalidOperationException(Strings.ETagAttribute_PropertyNameNotValid(propertyName, resourceType.FullName));
                    } 
 
                    if (property.TypeKind != ResourceTypeKind.Primitive)
                    { 
                        throw new InvalidOperationException(Strings.ETagAttribute_ETagPropertiesMustBeOfPrimitiveType(propertyName, resourceType.FullName));
                    }

                    // Ignore key properties if they are part of etag, since the uri already has the key information 
                    // and it makes no sense to duplicate them in etag
                    if (property.IsOfKind(ResourcePropertyKind.Key)) 
                    { 
                        throw new InvalidOperationException(Strings.ETagAttribute_KeyPropertiesCannotBePartOfETag(propertyName, resourceType.FullName));
                    } 

                    resourceType.AddETagProperty(property);
                }
            } 
        }
 
        ///  
        /// Writes the metadata for the given associations.
        ///  
        /// xmlWriter in which metadata needs to be written.
        /// associations whose metadata need to be written.
        private static void WriteAssociations(XmlWriter xmlWriter, IEnumerable associations)
        { 
            foreach (AssociationInfo association in associations)
            { 
                xmlWriter.WriteStartElement(XmlConstants.Association); 
                xmlWriter.WriteAttributeString(XmlConstants.Name, association.Name);
 
                foreach (EndInfo endInfo in association.Ends)
                {
                    xmlWriter.WriteStartElement(XmlConstants.End);
                    xmlWriter.WriteAttributeString(XmlConstants.Role, endInfo.Name); 

                    // The ends are of reference type 
                    xmlWriter.WriteAttributeString(XmlConstants.Type, endInfo.Type.FullName); 

                    // Write the multiplicity value 
                    xmlWriter.WriteAttributeString(XmlConstants.Multiplicity, endInfo.Multiplicity);
                    xmlWriter.WriteEndElement();
                }
 
                xmlWriter.WriteEndElement();
            } 
        } 

        ///  
        /// Writes the metadata for association sets for the given associations.
        /// 
        /// xmlWriter in which metadata needs to be written
        /// associations for which association sets needs to be written. 
        private void WriteAssociationSets(XmlWriter xmlWriter, IEnumerable associations)
        { 
            foreach (AssociationInfo association in associations) 
            {
                xmlWriter.WriteStartElement(XmlConstants.AssociationSet); 
                xmlWriter.WriteAttributeString(XmlConstants.Name, association.Name);
                xmlWriter.WriteAttributeString(XmlConstants.Association, association.FullName);
                foreach (EndInfo endInfo in association.Ends)
                { 
                    xmlWriter.WriteStartElement(XmlConstants.End);
                    xmlWriter.WriteAttributeString(XmlConstants.Role, endInfo.Name); 
 
                    // The ends are of reference type
                    ResourceContainer container = this.GetContainerForResourceType(endInfo.Type.Type); 
                    xmlWriter.WriteAttributeString(XmlConstants.EntitySet, container.Name);
                    xmlWriter.WriteEndElement();
                }
 
                xmlWriter.WriteEndElement();
            } 
        } 

        ///  
        /// Writes the entity container definition
        /// 
        /// xmlWriter into which metadata is written
        /// name of the entity container 
        /// list of entity set name and containing element type name
        /// associations for which association sets metadata needs to be written. 
        private void WriteEntityContainer( 
            XmlWriter xmlWriter,
            string entityContainerName, 
            IEnumerable> entitySets,
            Dictionary associations)
        {
            xmlWriter.WriteStartElement(XmlConstants.EntityContainer); 
            xmlWriter.WriteAttributeString(XmlConstants.Name, entityContainerName);
 
            // Since reflection based provider supports only one entity container, we should write the 
            // default entity container attribute for the only entity container
            BaseServiceProvider.WriteDataWebMetadata(xmlWriter, XmlConstants.IsDefaultEntityContainerAttribute, XmlConstants.XmlTrueLiteral); 

            foreach (KeyValuePair entitySet in entitySets)
            {
                ResourceContainer container = entitySet.Value; 
                xmlWriter.WriteStartElement(XmlConstants.EntitySet);
                xmlWriter.WriteAttributeString(XmlConstants.Name, entitySet.Key); 
                xmlWriter.WriteAttributeString(XmlConstants.EntityType, container.ResourceType.FullName); 

#if ASTORIA_CONTAINMENT 

                if (container.ContainmentCanonicalParent != null)
                {
                    xmlWriter.WriteAttributeString( 
                        XmlConstants.DataWebAccessTopLevelAccessAttribute,
                        XmlConstants.DataWebMetadataNamespace, 
                        XmlConvert.ToString(container.TopLevelAccess)); 
                }
 
#endif

                xmlWriter.WriteEndElement();
            } 

            this.WriteAssociationSets(xmlWriter, associations.Values); 
            this.WriteServiceOperations(xmlWriter, this.ServiceOperations); 
            xmlWriter.WriteEndElement();
        } 

        /// 
        /// Stores information about an end of an association.
        ///  
        private struct EndInfo
        { 
            /// Name of the relationship end  
            internal readonly string Name;
 
            /// Type of the relationship end.
            internal readonly ResourceType Type;

            /// Mulitplicity of the relationship end  
            internal readonly string Multiplicity;
 
            ///  
            /// Creates a new instance of EndInfo.
            ///  
            /// name of the end.
            /// resource type that the end refers to.
            /// multiplicity of the end.
            internal EndInfo(string name, ResourceType type, string multiplicity) 
            {
                this.Name = name; 
                this.Type = type; 
                this.Multiplicity = multiplicity;
            } 
        }

        /// 
        /// Stores information about a association and its ends 
        /// 
        private class AssociationInfo 
        { 
            /// FullName of the association.
            internal readonly string FullName; 

            /// Name of the association 
            internal readonly string Name;
 
            /// collection of ends for this association.
            internal readonly EndInfo[] Ends; 
 
            /// 
            /// Creates a new instance of AssociationInfo to store information about an association. 
            /// 
            /// name of the association.
            /// namespaceName of the association.
            /// first end of the association. 
            /// second end of the association.
            internal AssociationInfo(string name, string namespaceName, EndInfo end1, EndInfo end2) 
            { 
                this.Name = name;
                this.FullName = namespaceName + "." + name; 
                this.Ends = new EndInfo[] { end1, end2 };
            }
        }
 
        /// 
        /// Finds all the interesting types and their members given the top level type. 
        ///  
        private class TypeManager
        { 
            /// List of namespace along with the types in that namespace
            private Dictionary> namespaceManager = new Dictionary>(StringComparer.Ordinal);

            ///  
            /// Constructs a new instance of TypeManager using the knownTypes
            ///  
            /// list of known resource types 
            internal TypeManager(IEnumerable knownTypes)
            { 
                foreach (ResourceType resourceType in knownTypes)
                {
                    // Ignore Primitive types
                    if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive) 
                    {
                        continue; 
                    } 

                    List typesInSameNamespace; 
                    string typeNamespace = WebUtil.GetModelTypeNamespace(resourceType.Type);
                    if (!this.namespaceManager.TryGetValue(typeNamespace, out typesInSameNamespace))
                    {
                        typesInSameNamespace = new List(); 
                        this.namespaceManager.Add(typeNamespace, typesInSameNamespace);
                    } 
 
                    // Add the type to the list of types in the same namespace
                    typesInSameNamespace.Add(resourceType); 
                }
            }

            ///  
            /// Returns the list of namespace and the types in those namespaces
            ///  
            internal IEnumerable>> NamespaceAlongWithTypes 
            {
                get 
                {
                    return this.namespaceManager;
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK