DataServiceProviderWrapper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Providers / DataServiceProviderWrapper.cs / 1305376 / DataServiceProviderWrapper.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides the wrapper over IDataServiceMetadataProvider and IDataServiceQueryProvider calls
//      so that we can bunch of validation in one place. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections.Generic;
    using System.Data.Services.Serializers; 
    using System.Diagnostics;
    using System.Linq;
    using System.Xml;
    using System.Data.Services.Caching; 
    using System.Reflection;
 
    #endregion Namespaces. 

    /// Schema version compliance of the metadata. 
    internal enum MetadataEdmSchemaVersion
    {
        /// EDM v1.0 compliant.
        Version1Dot0, 

        /// EDM v1.1 compliant. 
        Version1Dot1, 

        /// EDM v1.2 compliant. 
        Version1Dot2,

        /// EDM v2.0 compliant.
        Version2Dot0, 
    }
 
    ///  
    /// Class to abstract IDataServiceMetadataProvider and IDataServiceQueryProvider,
    /// hence making sure all the metadata and query provider calls are made via this class. 
    ///
    /// Each request must create a new instance of this class because a
    /// request is the defined scope of metadata consistency.
    ///  
    internal class DataServiceProviderWrapper
    { 
        #region Private Fields 

        ///  
        /// Object reference that represents true. This is a workaround to the issue that 'Dictionary<string, bool>' will require
        /// JIT compilation at runtime for precompiled assemblies.  So we use 'Dictionary<string, object>' instead.
        /// 
        private static readonly object RefTrue = new object(); 

        ///  
        /// Object reference that represents false. This is a workaround to the issue that 'Dictionary<string, bool>' will require 
        /// JIT compilation at runtime for precompiled assemblies.  So we use 'Dictionary<string, object>' instead.
        ///  
        private static readonly object RefFalse = new object();

        /// 
        /// Empty open property values 
        /// 
        private static readonly IEnumerable> EmptyOpenPropertyValues = new KeyValuePair[0]; 
 
        /// 
        /// Metadata to be used by the service provider wrapper. 
        /// 
        private readonly MetadataCacheItem metadata;

        ///  
        /// metadata provider instance.
        ///  
        private IDataServiceMetadataProvider metadataProvider; 

        ///  
        /// metadata provider instance.
        /// 
        private IDataServiceQueryProvider queryProvider;
 
        #endregion Private Fields
 
        #region Constructors 

        ///  
        /// Creates a new instance of DataServiceProviderWrapper instance.
        /// 
        /// Metadata to be used by the service provider wrapper.
        /// instance of the metadata provider. 
        /// instance of the query provider.
        internal DataServiceProviderWrapper(MetadataCacheItem metadata, IDataServiceMetadataProvider metadataProvider, IDataServiceQueryProvider queryProvider) 
        { 
            Debug.Assert(metadata != null, "metadata != null");
            Debug.Assert(metadataProvider != null, "metadataProvider != null"); 
            Debug.Assert(queryProvider != null, "queryProvider != null");
            Debug.Assert(
                metadataProvider is BaseServiceProvider && queryProvider is BaseServiceProvider || (metadata.ResourceSetWrapperCache.Count == 0 && metadata.VisibleTypeCache.Count == 0),
                "For V1 providers, both metadata and query providers must be BaseServiceProvider, otherwise the metadata cache must be empty for IDSP providers"); 

            this.metadata = metadata; 
            this.metadataProvider = metadataProvider; 
            this.queryProvider = queryProvider;
        } 

        #endregion Constructors

        #region IDataServiceQueryProvider Properties 

        /// The data source from which data is provided. 
        public object CurrentDataSource 
        {
            get { return this.queryProvider.CurrentDataSource; } 
        }

        /// Gets a value indicating whether null propagation is required in expression trees.
        public bool NullPropagationRequired 
        {
            get { return this.queryProvider.IsNullPropagationRequired; } 
        } 

        #endregion IDataServiceQueryProvider Properties 

        #region IDataServiceMetadataProvider Properties

        /// Namespace name for the container. 
        public string ContainerNamespace
        { 
            get 
            {
                string containerNamespace = this.metadataProvider.ContainerNamespace; 

                // 752636 [Breaking Change]: Reflection Provider should not allow null ContainerNamespace
                // In V1 the reflection provider allows the namespace to be null. Fixing this would be a breaking change.
                // We will skip this check for V1 providers for now. 
                if (string.IsNullOrEmpty(containerNamespace) && !this.IsV1Provider)
                { 
                    throw new InvalidOperationException(Strings.DataServiceProviderWrapper_ContainerNamespaceMustNotBeNullOrEmpty); 
                }
 
                return containerNamespace;
            }
        }
 
        /// Name of the container
        public string ContainerName 
        { 
            get
            { 
                string containerName = this.metadataProvider.ContainerName;
                if (string.IsNullOrEmpty(containerName))
                {
                    throw new InvalidOperationException(Strings.DataServiceProviderWrapper_ContainerNameMustNotBeNullOrEmpty); 
                }
 
                return containerName; 
            }
        } 

        /// 
        /// Gets all visible containers.
        /// WARNING!!! This property can only be called for the $metadata path because it enumerates through all resource sets. 
        /// Calling it from outside of the $metadata path would break our IDSP contract.
        ///  
        public IEnumerable ResourceSets 
        {
            get 
            {
                var resourceSets = this.metadataProvider.ResourceSets;
                if (resourceSets != null)
                { 
                    HashSet resourceSetNames = new HashSet(EqualityComparer.Default);
 
                    foreach (ResourceSet resourceSet in resourceSets) 
                    {
                        // verify that the name of the resource set is unique 
                        AddUniqueNameToSet(
                            resourceSet != null ? resourceSet.Name : null,
                            resourceSetNames,
                            Strings.DataServiceProviderWrapper_MultipleEntitySetsWithSameName(resourceSet.Name)); 

                        // For IDSP, we want to make sure the metadata object instance stay the same within 
                        // a request because we do reference comparisons.  Note the provider can return 
                        // different metadata instances within the same request.  The the Validate*() methods
                        // will make sure to return the first cached instance. 
                        ResourceSetWrapper resourceSetWrapper = this.ValidateResourceSet(resourceSet);
                        if (resourceSetWrapper != null)
                        {
                            yield return resourceSetWrapper; 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// Returns all types in this data source
        /// WARNING!!! This property can only be called for the $metadata path because it enumerates through all resource types. 
        /// Calling it from outside of the $metadata path would break our IDSP contract.
        ///  
        public IEnumerable Types 
        {
            get 
            {
                var types = this.metadataProvider.Types;
                if (types != null)
                { 
                    HashSet resourceTypeNames = new HashSet(EqualityComparer.Default);
 
                    foreach (ResourceType resourceType in types) 
                    {
                        // verify that the name of the resource type is unique 
                        AddUniqueNameToSet(
                            resourceType != null ? resourceType.Name : null,
                            resourceTypeNames,
                            Strings.DataServiceProviderWrapper_MultipleResourceTypesWithSameName(resourceType.Name)); 

                        // For IDSP, we want to make sure the metadata object instance stay the same within 
                        // a request because we do reference comparisons.  Note the provider can return 
                        // different metadata instances within the same request.  The the Validate*() methods
                        // will make sure to return the first cached instance. 
                        ResourceType type = this.ValidateResourceType(resourceType);
                        if (type != null)
                        {
                            yield return type; 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// Returns all the visible service operations in this data source.
        /// WARNING!!! This property can only be called for the $metadata path because it enumerates through all service operations. 
        /// Calling it from outside of the $metadata path would break our IDSP contract.
        ///  
        public IEnumerable ServiceOperations 
        {
            get 
            {
                var serviceOperations = this.metadataProvider.ServiceOperations;
                if (serviceOperations != null)
                { 
                    HashSet serviceOperationNames = new HashSet(EqualityComparer.Default);
 
                    foreach (ServiceOperation serviceOperation in serviceOperations) 
                    {
                        // verify that the name of the service operation is unique 
                        AddUniqueNameToSet(
                            serviceOperation != null ? serviceOperation.Name : null,
                            serviceOperationNames,
                            Strings.DataServiceProviderWrapper_MultipleServiceOperationsWithSameName(serviceOperation.Name)); 

                        // For IDSP, we want to make sure the metadata object instance stay the same within 
                        // a request because we do reference comparisons.  Note the provider can return 
                        // different metadata instances within the same request.  The the Validate*() methods
                        // will make sure to return the first cached instance. 
                        ServiceOperationWrapper serviceOperationWrapper = this.ValidateServiceOperation(serviceOperation);
                        if (serviceOperationWrapper != null)
                        {
                            yield return serviceOperationWrapper; 
                        }
                    } 
                } 
            }
        } 

        #endregion IDataServiceMetadataProvider Properties

        #region Properties 

        ///  
        /// Cached configuration with access rights info. 
        /// 
        internal DataServiceConfiguration Configuration 
        {
            [DebuggerStepThrough]
            get { return this.metadata.Configuration; }
        } 

#if DEBUG 
        ///  
        /// Used for verifying expression generated for queries, checks if all the
        ///  
        internal bool AreAllResourceTypesNonOpen
        {
            get
            { 
                return !this.VisibleTypeCache.Values.Any(rt => rt.IsOpenType);
            } 
        } 
#endif
 
        /// 
        /// Returns true if the data provider is a V1 provider i.e. ReflectionServiceProvider or ObjectContextServiceProvider.
        /// Otherwise returns false.
        ///  
        internal bool IsV1Provider
        { 
            get { return this.metadataProvider is BaseServiceProvider; } 
        }
 
        /// 
        /// Returns the  for this provider
        /// 
        /// The  for this provider 
        /// Note that this will only return non-null on V1 providers
        /// in which case it returns our V1 provider's implementation of this interface. 
        /// In all other cases this returns null as we don't allow custom implementation of this interface yet. 
        internal IProjectionProvider ProjectionProvider
        { 
            get
            {
                if (this.IsV1Provider)
                { 
                    return (IProjectionProvider)this.metadataProvider;
                } 
                else 
                {
                    return null; 
                }
            }
        }
 
        /// 
        /// Keep track of the calculated visibility of resource types. 
        ///  
        private Dictionary VisibleTypeCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.VisibleTypeCache; }
        }
 
        /// 
        /// Maps resource set names to ResourceSetWrappers. 
        ///  
        private Dictionary ResourceSetWrapperCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ResourceSetWrapperCache; }
        }
 
        /// 
        /// Maps service operation names to ServiceOperationWrappers. 
        ///  
        private Dictionary ServiceOperationWrapperCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ServiceOperationWrapperCache; }
        }
 
        /// 
        /// Maps names to ResourceAssociationSets. 
        ///  
        private Dictionary ResourceAssociationSetCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ResourceAssociationSetCache; }
        }
 
        /// 
        /// Mapes "resourceSetName_resourceTypeName" to the list of visible properties from the set. 
        ///  
        private Dictionary> ResourcePropertyCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ResourcePropertyCache; }
        }
 
        /// 
        /// Mapes "resourceSetName_resourceTypeName" to boolean of whether resourceType is allowed for resourceSet 
        ///  
        private Dictionary EntityTypeDisallowedForSet
        { 
            [DebuggerStepThrough]
            get { return this.metadata.EntityTypeDisallowedForSet; }
        }
 
        #endregion Properties
 
        #region IDataServiceQueryProvider Methods 

#if DEBUG 
        /// 
        /// Returns the IQueryable that represents the container.
        /// 
        /// resource set representing the entity set. 
        /// 
        /// An IQueryable that represents the container; null if there is 
        /// no container for the specified name. 
        /// 
        public IQueryable GetQueryRootForResourceSet(ResourceSetWrapper resourceSet, IDataService dataService) 
#else
        /// 
        /// Returns the IQueryable that represents the container.
        ///  
        /// resource set representing the entity set.
        ///  
        /// An IQueryable that represents the container; null if there is 
        /// no container for the specified name.
        ///  
        public IQueryable GetQueryRootForResourceSet(ResourceSetWrapper resourceSet)
#endif
        {
            Debug.Assert(resourceSet != null, "resourceSet != null"); 
#if DEBUG
            dataService.ProcessingPipeline.AssertDebugStateDuringRequestProcessing(dataService); 
#endif 
            return this.queryProvider.GetQueryRootForResourceSet(resourceSet.ResourceSet);
        } 

        /// Gets the  for the specified .
        /// Instance to extract a  from.
        /// The  that describes this  in this provider. 
        public ResourceType GetResourceType(object instance)
        { 
            Debug.Assert(instance != null, "instance != null"); 
            return this.ValidateResourceType(this.queryProvider.GetResourceType(instance));
        } 

        /// 
        /// Get the value of the strongly typed property.
        ///  
        /// instance of the type declaring the property.
        /// resource property describing the property. 
        /// Resource type to which the property belongs. 
        /// value for the property.
        public object GetPropertyValue(object target, ResourceProperty resourceProperty, ResourceType resourceType) 
        {
            Debug.Assert(target != null, "target != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
            Debug.Assert(resourceProperty.IsReadOnly, "resourceProperty.IsReadOnly"); 
            if (resourceProperty.CanReflectOnInstanceTypeProperty)
            { 
                try 
                {
                    if (resourceType == null) 
                    {
                        resourceType = this.GetResourceType(target);
                    }
 
                    Debug.Assert(resourceType != null, "resourceType != null");
                    PropertyInfo propertyInfo = resourceType.GetPropertyInfo(resourceProperty); 
                    Debug.Assert(propertyInfo != null, "propertyInfo != null"); 
                    return propertyInfo.GetGetMethod().Invoke(target, null);
                } 
                catch (TargetInvocationException exception)
                {
                    ErrorHandler.HandleTargetInvocationException(exception);
                    throw; 
                }
            } 
            else 
            {
                return this.queryProvider.GetPropertyValue(target, resourceProperty); 
            }
        }

        ///  
        /// Get the value of the open property.
        ///  
        /// instance of the type declaring the open property. 
        /// name of the open property.
        /// value for the open property. 
        public object GetOpenPropertyValue(object target, string propertyName)
        {
            Debug.Assert(target != null, "target != null");
            Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); 
            return this.queryProvider.GetOpenPropertyValue(target, propertyName);
        } 
 
        /// 
        /// Get the name and values of all the properties defined in the given instance of an open type. 
        /// 
        /// instance of a open type.
        /// collection of name and values of all the open properties.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "need to return a collection of key value pair")] 
        public IEnumerable> GetOpenPropertyValues(object target)
        { 
            Debug.Assert(target != null, "target != null"); 
            IEnumerable> result = this.queryProvider.GetOpenPropertyValues(target);
            if (result == null) 
            {
                return EmptyOpenPropertyValues;
            }
 
            return result;
        } 
 
        /// 
        /// Invoke the given service operation and returns the results. 
        /// 
        /// service operation to invoke.
        /// value of parameters to pass to the service operation.
        /// returns the result of the service operation. If the service operation returns void, then this should return null. 
        public object InvokeServiceOperation(ServiceOperationWrapper serviceOperation, object[] parameters)
        { 
            Debug.Assert(serviceOperation != null, "serviceOperation != null"); 
            return this.queryProvider.InvokeServiceOperation(serviceOperation.ServiceOperation, parameters);
        } 

        #endregion IDataServiceQueryProvider Methods

        #region IDataServiceMetadataProvider Methods 

        /// Given the specified name, tries to find a resource set. 
        /// Name of the resource set to resolve. 
        /// Resolved resource set, possibly null.
        public ResourceSetWrapper TryResolveResourceSet(string name) 
        {
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");

            // For IDSP, we want to make sure the metadata object instance stay the same within 
            // a request because we do reference comparisons.
            ResourceSetWrapper resourceSetWrapper; 
            if (this.ResourceSetWrapperCache.TryGetValue(name, out resourceSetWrapper)) 
            {
                return resourceSetWrapper; 
            }

            ResourceSet resourceSet;
            if (this.metadataProvider.TryResolveResourceSet(name, out resourceSet)) 
            {
                return this.ValidateResourceSet(resourceSet); 
            } 

            return null; 
        }

        /// 
        /// Gets the ResourceAssociationSet instance when given the source association end. 
        /// 
        /// Resource set of the source association end. 
        /// Resource type of the source association end. 
        /// Resource property of the source association end.
        /// ResourceAssociationSet instance. 
        public ResourceAssociationSet GetResourceAssociationSet(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
 
            // If the association set has already been cached, use the cached copy 
            resourceType = GetDeclaringTypeForProperty(resourceType, resourceProperty);
            string associationSetKey = resourceSet.Name + '_' + resourceType.FullName + '_' + resourceProperty.Name; 
            ResourceAssociationSet associationSet;
            if (this.ResourceAssociationSetCache.TryGetValue(associationSetKey, out associationSet))
            {
                return associationSet; 
            }
 
            // Get the association set from the underlying provider. 
            associationSet = this.metadataProvider.GetResourceAssociationSet(resourceSet.ResourceSet, resourceType, resourceProperty);
            if (associationSet != null) 
            {
                ResourceAssociationSetEnd thisEnd = associationSet.GetResourceAssociationSetEnd(resourceSet, resourceType, resourceProperty);
                ResourceAssociationSetEnd relatedEnd = associationSet.GetRelatedResourceAssociationSetEnd(resourceSet, resourceType, resourceProperty);
                ResourceSetWrapper relatedSet = this.ValidateResourceSet(relatedEnd.ResourceSet); 
                if (relatedSet == null)
                { 
                    // If the related set is not visible, the association set is also not visible. 
                    associationSet = null;
                } 
                else
                {
                    ResourceType relatedType = this.ValidateResourceType(relatedEnd.ResourceType);
                    ResourceProperty relatedProperty = null; 
                    if (relatedEnd.ResourceProperty != null)
                    { 
                        relatedProperty = relatedType.TryResolvePropertyName(relatedEnd.ResourceProperty.Name); 
                    }
 
                    // For IDSP, we want to make sure the metadata object instance stay the same within a request because we
                    // do reference comparisons.  Note if the provider returns a ResourceAssociationSet with different instances
                    // of ResourceSet, ResourceType and ResourceProperty than what we've seen earlier in the same request, we
                    // create a new instance of the association set using the metadata objects we've already cached. 
                    // If the metadata change should cause a failure, we want the IDSP to detect it and fail. At the Astoria runtime
                    // layer we assume the metadata objects to remain constant throughout the request. 
                    resourceType = this.ValidateResourceType(thisEnd.ResourceType); 
                    if (thisEnd.ResourceSet != resourceSet.ResourceSet ||
                        thisEnd.ResourceType != resourceType || 
                        thisEnd.ResourceProperty != resourceProperty ||
                        relatedEnd.ResourceSet != relatedSet.ResourceSet ||
                        relatedEnd.ResourceType != relatedType ||
                        relatedEnd.ResourceProperty != relatedProperty) 
                    {
                        associationSet = new ResourceAssociationSet( 
                            associationSet.Name, 
                            new ResourceAssociationSetEnd(resourceSet.ResourceSet, resourceType, resourceProperty),
                            new ResourceAssociationSetEnd(relatedSet.ResourceSet, relatedType, relatedProperty)); 
                    }
                }
            }
 
            this.ResourceAssociationSetCache.Add(associationSetKey, associationSet);
            return associationSet; 
        } 

        /// Given the specified name, tries to find a type. 
        /// Name of the type to resolve.
        /// Resolved resource type, possibly null.
        public ResourceType TryResolveResourceType(string name)
        { 
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");
 
            // For IDSP, we want to make sure the metadata object instance stay the same within 
            // a request because we do reference comparisons.
            ResourceType resourceType; 
            if (this.VisibleTypeCache.TryGetValue(name, out resourceType))
            {
                return resourceType;
            } 

            if (this.metadataProvider.TryResolveResourceType(name, out resourceType)) 
            { 
                return this.ValidateResourceType(resourceType);
            } 

            return null;
        }
 
        /// 
        /// The method must return a collection of all the types derived from . 
        /// The collection returned should NOT include the type passed in as a parameter. 
        /// An implementer of the interface should return null if the type does not have any derived types (ie. null == no derived types).
        ///  
        /// Resource to get derived resource types from.
        /// 
        /// A collection of resource types () derived from the specified 
        /// or null if there no types derived from the specified  exist. 
        /// 
        public IEnumerable GetDerivedTypes(ResourceType resourceType) 
        { 
            Debug.Assert(resourceType != null, "resourceType != null");
 
            var derivedTypes = this.metadataProvider.GetDerivedTypes(resourceType);
            if (derivedTypes != null)
            {
                foreach (ResourceType derivedType in derivedTypes) 
                {
                    ResourceType type = this.ValidateResourceType(derivedType); 
                    if (type != null) 
                    {
                        yield return type; 
                    }
                }
            }
        } 

        ///  
        /// Returns true if  represents an Entity Type which has derived Entity Types, else false. 
        /// 
        /// instance of the resource type in question. 
        /// True if  represents an Entity Type which has derived Entity Types, else false.
        public bool HasDerivedTypes(ResourceType resourceType)
        {
            Debug.Assert(this.ValidateResourceType(resourceType) != null, "resourceType must be read-only and visible."); 
            return this.metadataProvider.HasDerivedTypes(resourceType);
        } 
 
        /// Given the specified name, tries to find a service operation.
        /// Name of the service operation to resolve. 
        /// Resolved service operation, possibly null.
        public ServiceOperationWrapper TryResolveServiceOperation(string name)
        {
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)"); 

            // For IDSP, we want to make sure the metadata object instance stay the same within 
            // a request because we do reference comparisons. 
            ServiceOperationWrapper serviceOperationWrapper;
            if (this.ServiceOperationWrapperCache.TryGetValue(name, out serviceOperationWrapper)) 
            {
                return serviceOperationWrapper;
            }
 
            ServiceOperation serviceOperation;
            if (this.metadataProvider.TryResolveServiceOperation(name, out serviceOperation)) 
            { 
                return this.ValidateServiceOperation(serviceOperation);
            } 

            return null;
        }
 
        #endregion IDataServiceMetadataProvider Methods
 
        #region Internal Methods 

        ///  
        /// Gets the resource type which the resource property is declared on.
        /// 
        /// resource type to start looking
        /// resource property in question 
        /// actual resource type that declares the property
        internal static ResourceType GetDeclaringTypeForProperty(ResourceType resourceType, ResourceProperty resourceProperty) 
        { 
            Debug.Assert(resourceType != null, "resourceType != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 

            while (resourceType != null)
            {
                if (resourceType.TryResolvePropertiesDeclaredOnThisTypeByName(resourceProperty.Name) != null) 
                {
                    break; 
                } 

                resourceType = resourceType.BaseType; 
            }

            Debug.Assert(resourceType != null, "resourceType != null");
            return resourceType; 
        }
 
        /// Disposes of the metadata and query providers. 
        internal void DisposeDataSource()
        { 
            Debug.Assert(this.queryProvider != null, "this.queryProvider != null");
            Debug.Assert(this.metadataProvider != null, "this.metadataProvider != null");

            WebUtil.Dispose(this.metadataProvider); 

            // If the same instance implements IDataServiceMetadataProvider and IDataServiceQueryProvider interface, 
            // we call dispose only once. 
            if (this.metadataProvider != this.queryProvider)
            { 
                WebUtil.Dispose(this.queryProvider);
            }

            this.metadataProvider = null; 
            this.queryProvider = null;
        } 
 
        /// 
        /// Iterates through the resource sets, service operations and resource types to pre-populate the metadata cache item. 
        /// 
        internal void PopulateMetadataCacheItemForV1Provider()
        {
            Debug.Assert(this.IsV1Provider, "this.IsV1Provider"); 

            // This is only called when we initialize the service for the first time. 
            // The Count extention method will cause the iterator to instantiate the wrapper classes. 
            this.ServiceOperations.Count();
            this.Types.Count(); 

            foreach (ResourceSetWrapper resourceSet in this.ResourceSets)
            {
                // Derived types of a visible type are visible 
                foreach (ResourceType derivedType in this.GetDerivedTypes(resourceSet.ResourceType))
                { 
                    this.GetResourceProperties(resourceSet, derivedType); 
                    this.IsEntityTypeDisallowedForSet(resourceSet, derivedType);
                } 

                // Base types of a visible type are visible
                ResourceType resourceType = resourceSet.ResourceType;
                while (resourceType != null) 
                {
                    this.GetResourceProperties(resourceSet, resourceType); 
                    this.IsEntityTypeDisallowedForSet(resourceSet, resourceType); 
                    resourceType = resourceType.BaseType;
                } 
            }
        }

        ///  
        /// Gets the target container for the given navigation property, source container and the source resource type
        ///  
        /// source entity set. 
        /// source resource type.
        /// navigation property. 
        /// target container that the navigation property refers to.
        internal ResourceSetWrapper GetContainer(ResourceSetWrapper sourceContainer, ResourceType sourceResourceType, ResourceProperty navigationProperty)
        {
            ResourceAssociationSet associationSet = this.GetResourceAssociationSet(sourceContainer, sourceResourceType, navigationProperty); 
            if (associationSet != null)
            { 
                ResourceAssociationSetEnd relatedEnd = associationSet.GetRelatedResourceAssociationSetEnd(sourceContainer, sourceResourceType, navigationProperty); 
                return this.ValidateResourceSet(relatedEnd.ResourceSet);
            } 

            return null;
        }
 
        /// 
        /// For a V1 provider checks the Epm compatiblity in order to write the appropriate 
        /// versioning header for metadata requests 
        /// 
        /// true if the provider is V1 compatible, false otherwise 
        internal bool GetEpmCompatiblityForV1Provider()
        {
            Debug.Assert(this.IsV1Provider, "Must be a V1 provider to call this function");
            return (this.metadataProvider as BaseServiceProvider).EpmIsV1Compatible; 
        }
 
        ///  
        /// Return the list of ETag properties for a given type in the context of a given container
        ///  
        /// Name of the container to use for context (for MEST-enabled providers)
        /// Type to get the ETag properties for
        /// A collection of the properties that form the ETag for the given type in the given container
        internal IList GetETagProperties(string containerName, ResourceType resourceType) 
        {
            Debug.Assert(containerName != null || !(this.metadataProvider is ObjectContextServiceProvider), "ContainerName is required for MEST-enabled provider (EFx provider)"); 
            Debug.Assert(resourceType != null && resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Resource should be non-null and of an entity type"); 

            // Note only primitive properties can be part of an etag, they are always visible. 
            ObjectContextServiceProvider efxProvider = this.metadataProvider as ObjectContextServiceProvider;
            return efxProvider == null ? resourceType.ETagProperties :
                                         efxProvider.GetETagProperties(containerName, resourceType);
        } 

        ///  
        /// Gets the visible resource properties for  from . 
        /// We cache the list of visible resource properties so we don't have to calculate it repeatedly when serializing feeds.
        ///  
        /// Resource set in question.
        /// Resource type in question.
        /// List of visible resource properties from the given resource set and resource type.
        internal IEnumerable GetResourceProperties(ResourceSetWrapper resourceSet, ResourceType resourceType) 
        {
            Debug.Assert(resourceType != null, "resourceType != null"); 
            if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) 
            {
                Debug.Assert(resourceSet != null, "resourceSet != null"); 
                string key = resourceSet.Name + '_' + resourceType.FullName;
                List properties;
                if (!this.ResourcePropertyCache.TryGetValue(key, out properties))
                { 
                    properties = new List();
                    foreach (ResourceProperty property in resourceType.Properties) 
                    { 
                        if (property.TypeKind == ResourceTypeKind.EntityType && this.GetContainer(resourceSet, resourceType, property) == null)
                        { 
                            continue;
                        }

                        properties.Add(property); 
                    }
 
                    this.ResourcePropertyCache.Add(key, properties); 
                }
 
                return properties;
            }
            else
            { 
                return resourceType.Properties;
            } 
        } 

        ///  
        /// Write the metadata document.
        /// 
        /// instance of the metadata serializer.
        /// xml writer in which we need to write the metadata document. 
        /// Data service instance.
        internal void WriteMetadataDocument(MetadataSerializer serializer, XmlWriter writer, IDataService service) 
        { 
            Debug.Assert(serializer != null, "serializer != null");
            Debug.Assert(writer != null, "writer != null"); 

            BaseServiceProvider internalProvider = this.metadataProvider as BaseServiceProvider;
            ObjectContextServiceProvider efxProvider = this.metadataProvider as ObjectContextServiceProvider;
 
            // always v1.1+ schemas for custom providers
            MetadataEdmSchemaVersion metadataEdmSchemaVersion = internalProvider == null ? MetadataEdmSchemaVersion.Version1Dot1 : internalProvider.EdmSchemaVersion; 
 
            if (efxProvider == null)
            { 
                serializer.GenerateMetadata(metadataEdmSchemaVersion, service);
            }
            else
            { 
                efxProvider.GetMetadata(writer, this, service);
            } 
        } 

        ///  
        /// Check if the given type can be ordered. If not, throw an exception.
        /// 
        /// clr type which needs to checked for ordering.
        internal void CheckIfOrderedType(Type clrType) 
        {
            // For known providers check for sort-ability for better error reporting 
            BaseServiceProvider baseProvider = this.metadataProvider as BaseServiceProvider; 
            if (baseProvider != null &&
                !baseProvider.GetTypeIsOrdered(clrType)) 
            {
                string resourceTypeName = WebUtil.GetTypeName(clrType);
                throw DataServiceException.CreateBadRequestError(Strings.RequestQueryParser_OrderByDoesNotSupportType(resourceTypeName));
            } 
        }
 
        ///  
        /// Checks whether the current data provider is a V1 provider or not.
        ///  
        /// Returns true if the current data source is a V1 provider. Otherwise, returns false.
        internal bool IsV1ProviderAndImplementsUpdatable()
        {
            BaseServiceProvider baseServiceProvider = this.metadataProvider as BaseServiceProvider; 
            if (baseServiceProvider != null &&
                baseServiceProvider.ImplementsIUpdatable()) 
            { 
                return true;
            } 

            return false;
        }
 
        /// 
        /// Retrieve an implementation of a data service interface (ie. IUpdatable, IExpandProvider,etc) 
        ///  
        /// The type representing the requested interface
        /// Data service instance 
        /// An object implementing the requested interface, or null if not available
        internal T GetService(IDataService dataService) where T : class
        {
            Debug.Assert(dataService != null, "dataService != null"); 
            Debug.Assert(dataService.Provider == this, "dataService.Provider == this");
            Debug.Assert(typeof(T) != typeof(IDataServiceMetadataProvider), "typeof(T) != typeof(IDataServiceMetadataProvider)"); 
            Debug.Assert(typeof(T) != typeof(IDataServiceQueryProvider), "typeof(T) != typeof(IDataServiceQueryProvider)"); 
            Debug.Assert(typeof(T).IsVisible, "Trying to ask the service for non-public interface.");
 
#if DEBUG
            dataService.ProcessingPipeline.AssertDebugStateDuringRequestProcessing(dataService);
            dataService.ProcessingPipeline.HasInstantiatedProviderInterfaces = true;
#endif 
            // *NOTE* to limit test surface area, IDataServiceStreamProvider && IExpandProvider are the only custom implementation
            // we support for ObjectContextServiceProvider. 
            // Should remove this in the future. 
            if (this.metadataProvider is ObjectContextServiceProvider && typeof(T) != typeof(IDataServiceStreamProvider) && typeof(T) != typeof(IExpandProvider))
            { 
                // Return internal implementation of the interface if there is one.
                return WebUtil.GetService(this.metadataProvider);
            }
 
            // 1. Check if subclass of DataService implements IServiceProvider. If it does, then call IServiceProvider.GetService()
            // with the appropriate type. If it doesn’t proceed to Step 2 
            //    a. If IServiceProvider.GetService() returns something, then go ahead and use that instance 
            //    b. If IServiceProvider.GetService() doesn't return anything, proceed to Step 2.
            T result = WebUtil.GetService(dataService.Instance); 
            if (result != null)
            {
                return result;
            } 

            // 2. Check if the T (where T is the type from DataService) implements the interface. 
            //    a. If yes, use that. 
            //    b. If no, proceed to Step 3
            result = this.CurrentDataSource as T; 
            if (result != null)
            {
                // Since IDataServiceUpdateProvider derives from IUpdatable, we need to make sure that
                // when asked for IUpdatable, this method checks only for IUpdatable, and returns null 
                // if the type returns IDataServiceUpdateProvider.
                if (typeof(T) != typeof(IUpdatable) || ((result as IDataServiceUpdateProvider) == null)) 
                { 
                    return result;
                } 
            }

            // 3. Check if the data service provider is a V1 provider
            //    a. If yes, return an internal implementation if we can find one. 
            //    b. If no, then the provider doesn’t support the current interface functionality.
            if (this.IsV1Provider) 
            { 
                // Look for internal implementation for the interface
                return WebUtil.GetService(this.metadataProvider); 
            }

            return null;
        } 

        ///  
        /// We do not allow entity sets to contain any derived type with navigation properties in the GET path 
        /// 
        /// entity set containing the resource type. 
        /// entity type in the hierarchy returned by .
        /// True if the derived type has any navigation properties.
        internal bool IsEntityTypeDisallowedForSet(ResourceSetWrapper resourceSet, ResourceType resourceType)
        { 
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null"); 
 
            object result;
            string key = resourceSet.Name + '_' + resourceType.FullName; 
            if (this.EntityTypeDisallowedForSet.TryGetValue(key, out result))
            {
                Debug.Assert(result == DataServiceProviderWrapper.RefTrue || result == DataServiceProviderWrapper.RefFalse, "result must be either RefTrue or RefFalse.");
                return result == DataServiceProviderWrapper.RefTrue ? true : false; 
            }
 
            ResourceType baseType = resourceSet.ResourceType; 
            if (baseType != resourceType && baseType.IsAssignableFrom(resourceType) && this.HasNavigationProperties(resourceSet, resourceType))
            { 
                this.EntityTypeDisallowedForSet.Add(key, DataServiceProviderWrapper.RefTrue);
                return true;
            }
            else 
            {
                this.EntityTypeDisallowedForSet.Add(key, DataServiceProviderWrapper.RefFalse); 
                return false; 
            }
        } 

        /// 
        /// Validates if the container should be visible and is not read only. If the container rights
        /// are set to None the container should not be visible. 
        /// 
        /// Resource set to be validated. 
        /// Validated container, null if the container is not supposed to be visible. 
        internal ResourceSetWrapper ValidateResourceSet(ResourceSet resourceSet)
        { 
            ResourceSetWrapper resourceSetWrapper = null;
            if (resourceSet != null)
            {
                // For IDSP, we want to make sure the metadata object instance stay the same within 
                // a request because we do reference comparisons.  Note the provider can return
                // different metadata instances within the same request.  The the Validate*() methods 
                // will make sure to return the first cached instance. 
                if (this.ResourceSetWrapperCache.TryGetValue(resourceSet.Name, out resourceSetWrapper))
                { 
                    return resourceSetWrapper;
                }

                resourceSetWrapper = new ResourceSetWrapper(resourceSet, this.ValidateResourceType(resourceSet.ResourceType)); 
                resourceSetWrapper.ApplyConfiguration(this.Configuration);
                if (!resourceSetWrapper.IsVisible) 
                { 
                    resourceSetWrapper = null;
                } 

                this.ResourceSetWrapperCache[resourceSet.Name] = resourceSetWrapper;
            }
 
            return resourceSetWrapper;
        } 
 
        #endregion Internal Methods
 
        #region Private Methods

        /// 
        /// Throws if resource type is not sealed. 
        /// 
        /// resource type to inspect. 
        private static void ValidateResourceTypeReadOnly(ResourceType resourceType) 
        {
            Debug.Assert(resourceType != null, "resourceType != null"); 
            if (!resourceType.IsReadOnly)
            {
                throw new DataServiceException(500, Strings.DataServiceProviderWrapper_ResourceTypeNotReadonly(resourceType.FullName));
            } 
        }
 
        ///  
        /// This is a common method for checking uniqe names across entity sets, resource types and service operations.
        ///  
        /// Name to be added to set.
        /// Set containing already verified names.
        /// String for exception to be thrown if the name is not unique.
        private static void AddUniqueNameToSet(string name, HashSet names, string exceptionString) 
        {
            if (name != null) 
            { 
                if (names.Contains(name))
                { 
                    throw new DataServiceException(500, exceptionString);
                }

                names.Add(name); 
            }
        } 
 
        /// Validates that  is cached and read only.
        /// Resource type to be validated. 
        /// Validated resource type, null if the resource type is not supposed to be visible.
        private ResourceType ValidateResourceType(ResourceType resourceType)
        {
            if (resourceType != null) 
            {
                // For IDSP, we want to make sure the metadata object instance stay the same within 
                // a request because we do reference comparisons.  Note the provider can return 
                // different metadata instances within the same request.  The the Validate*() methods
                // will make sure to return the first cached instance. 
                ResourceType cachedType;
                if (this.VisibleTypeCache.TryGetValue(resourceType.FullName, out cachedType))
                {
                    return cachedType; 
                }
 
                ValidateResourceTypeReadOnly(resourceType); 
                this.VisibleTypeCache[resourceType.FullName] = resourceType;
                return resourceType; 
            }

            return null;
        } 

        ///  
        /// Validates if the service operation should be visible and is read only. If the service operation 
        /// rights are set to None the service operation should not be visible.
        ///  
        /// Service operation to be validated.
        /// Validated service operation, null if the service operation is not supposed to be visible.
        private ServiceOperationWrapper ValidateServiceOperation(ServiceOperation serviceOperation)
        { 
            ServiceOperationWrapper serviceOperationWrapper = null;
            if (serviceOperation != null) 
            { 
                // For IDSP, we want to make sure the metadata object instance stay the same within
                // a request because we do reference comparisons.  Note the provider can return 
                // different metadata instances within the same request.  The the Validate*() methods
                // will make sure to return the first cached instance.
                if (this.ServiceOperationWrapperCache.TryGetValue(serviceOperation.Name, out serviceOperationWrapper))
                { 
                    return serviceOperationWrapper;
                } 
 
                serviceOperationWrapper = new ServiceOperationWrapper(serviceOperation);
                serviceOperationWrapper.ApplyConfiguration(this.Configuration, this); 
                if (!serviceOperationWrapper.IsVisible)
                {
                    serviceOperationWrapper = null;
                } 

                this.ServiceOperationWrapperCache[serviceOperation.Name] = serviceOperationWrapper; 
            } 

            return serviceOperationWrapper; 
        }

        /// 
        /// Checks whether the resource type from the resource set has visible navigation properties or not. 
        /// 
        /// resource set instance to inspect. 
        /// resource type to inspect. 
        /// Returns true if the resource type has one or more visible navigation properties from the resource set. Otherwise returns false.
        private bool HasNavigationProperties(ResourceSetWrapper resourceSet, ResourceType resourceType) 
        {
            foreach (ResourceProperty property in resourceType.PropertiesDeclaredOnThisType)
            {
                if (property.TypeKind != ResourceTypeKind.EntityType) 
                {
                    continue; 
                } 

                if (this.GetResourceAssociationSet(resourceSet, resourceType, property) != null) 
                {
                    return true;
                }
            } 

            return false; 
        } 

        #endregion Private Methods 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides the wrapper over IDataServiceMetadataProvider and IDataServiceQueryProvider calls
//      so that we can bunch of validation in one place. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections.Generic;
    using System.Data.Services.Serializers; 
    using System.Diagnostics;
    using System.Linq;
    using System.Xml;
    using System.Data.Services.Caching; 
    using System.Reflection;
 
    #endregion Namespaces. 

    /// Schema version compliance of the metadata. 
    internal enum MetadataEdmSchemaVersion
    {
        /// EDM v1.0 compliant.
        Version1Dot0, 

        /// EDM v1.1 compliant. 
        Version1Dot1, 

        /// EDM v1.2 compliant. 
        Version1Dot2,

        /// EDM v2.0 compliant.
        Version2Dot0, 
    }
 
    ///  
    /// Class to abstract IDataServiceMetadataProvider and IDataServiceQueryProvider,
    /// hence making sure all the metadata and query provider calls are made via this class. 
    ///
    /// Each request must create a new instance of this class because a
    /// request is the defined scope of metadata consistency.
    ///  
    internal class DataServiceProviderWrapper
    { 
        #region Private Fields 

        ///  
        /// Object reference that represents true. This is a workaround to the issue that 'Dictionary<string, bool>' will require
        /// JIT compilation at runtime for precompiled assemblies.  So we use 'Dictionary<string, object>' instead.
        /// 
        private static readonly object RefTrue = new object(); 

        ///  
        /// Object reference that represents false. This is a workaround to the issue that 'Dictionary<string, bool>' will require 
        /// JIT compilation at runtime for precompiled assemblies.  So we use 'Dictionary<string, object>' instead.
        ///  
        private static readonly object RefFalse = new object();

        /// 
        /// Empty open property values 
        /// 
        private static readonly IEnumerable> EmptyOpenPropertyValues = new KeyValuePair[0]; 
 
        /// 
        /// Metadata to be used by the service provider wrapper. 
        /// 
        private readonly MetadataCacheItem metadata;

        ///  
        /// metadata provider instance.
        ///  
        private IDataServiceMetadataProvider metadataProvider; 

        ///  
        /// metadata provider instance.
        /// 
        private IDataServiceQueryProvider queryProvider;
 
        #endregion Private Fields
 
        #region Constructors 

        ///  
        /// Creates a new instance of DataServiceProviderWrapper instance.
        /// 
        /// Metadata to be used by the service provider wrapper.
        /// instance of the metadata provider. 
        /// instance of the query provider.
        internal DataServiceProviderWrapper(MetadataCacheItem metadata, IDataServiceMetadataProvider metadataProvider, IDataServiceQueryProvider queryProvider) 
        { 
            Debug.Assert(metadata != null, "metadata != null");
            Debug.Assert(metadataProvider != null, "metadataProvider != null"); 
            Debug.Assert(queryProvider != null, "queryProvider != null");
            Debug.Assert(
                metadataProvider is BaseServiceProvider && queryProvider is BaseServiceProvider || (metadata.ResourceSetWrapperCache.Count == 0 && metadata.VisibleTypeCache.Count == 0),
                "For V1 providers, both metadata and query providers must be BaseServiceProvider, otherwise the metadata cache must be empty for IDSP providers"); 

            this.metadata = metadata; 
            this.metadataProvider = metadataProvider; 
            this.queryProvider = queryProvider;
        } 

        #endregion Constructors

        #region IDataServiceQueryProvider Properties 

        /// The data source from which data is provided. 
        public object CurrentDataSource 
        {
            get { return this.queryProvider.CurrentDataSource; } 
        }

        /// Gets a value indicating whether null propagation is required in expression trees.
        public bool NullPropagationRequired 
        {
            get { return this.queryProvider.IsNullPropagationRequired; } 
        } 

        #endregion IDataServiceQueryProvider Properties 

        #region IDataServiceMetadataProvider Properties

        /// Namespace name for the container. 
        public string ContainerNamespace
        { 
            get 
            {
                string containerNamespace = this.metadataProvider.ContainerNamespace; 

                // 752636 [Breaking Change]: Reflection Provider should not allow null ContainerNamespace
                // In V1 the reflection provider allows the namespace to be null. Fixing this would be a breaking change.
                // We will skip this check for V1 providers for now. 
                if (string.IsNullOrEmpty(containerNamespace) && !this.IsV1Provider)
                { 
                    throw new InvalidOperationException(Strings.DataServiceProviderWrapper_ContainerNamespaceMustNotBeNullOrEmpty); 
                }
 
                return containerNamespace;
            }
        }
 
        /// Name of the container
        public string ContainerName 
        { 
            get
            { 
                string containerName = this.metadataProvider.ContainerName;
                if (string.IsNullOrEmpty(containerName))
                {
                    throw new InvalidOperationException(Strings.DataServiceProviderWrapper_ContainerNameMustNotBeNullOrEmpty); 
                }
 
                return containerName; 
            }
        } 

        /// 
        /// Gets all visible containers.
        /// WARNING!!! This property can only be called for the $metadata path because it enumerates through all resource sets. 
        /// Calling it from outside of the $metadata path would break our IDSP contract.
        ///  
        public IEnumerable ResourceSets 
        {
            get 
            {
                var resourceSets = this.metadataProvider.ResourceSets;
                if (resourceSets != null)
                { 
                    HashSet resourceSetNames = new HashSet(EqualityComparer.Default);
 
                    foreach (ResourceSet resourceSet in resourceSets) 
                    {
                        // verify that the name of the resource set is unique 
                        AddUniqueNameToSet(
                            resourceSet != null ? resourceSet.Name : null,
                            resourceSetNames,
                            Strings.DataServiceProviderWrapper_MultipleEntitySetsWithSameName(resourceSet.Name)); 

                        // For IDSP, we want to make sure the metadata object instance stay the same within 
                        // a request because we do reference comparisons.  Note the provider can return 
                        // different metadata instances within the same request.  The the Validate*() methods
                        // will make sure to return the first cached instance. 
                        ResourceSetWrapper resourceSetWrapper = this.ValidateResourceSet(resourceSet);
                        if (resourceSetWrapper != null)
                        {
                            yield return resourceSetWrapper; 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// Returns all types in this data source
        /// WARNING!!! This property can only be called for the $metadata path because it enumerates through all resource types. 
        /// Calling it from outside of the $metadata path would break our IDSP contract.
        ///  
        public IEnumerable Types 
        {
            get 
            {
                var types = this.metadataProvider.Types;
                if (types != null)
                { 
                    HashSet resourceTypeNames = new HashSet(EqualityComparer.Default);
 
                    foreach (ResourceType resourceType in types) 
                    {
                        // verify that the name of the resource type is unique 
                        AddUniqueNameToSet(
                            resourceType != null ? resourceType.Name : null,
                            resourceTypeNames,
                            Strings.DataServiceProviderWrapper_MultipleResourceTypesWithSameName(resourceType.Name)); 

                        // For IDSP, we want to make sure the metadata object instance stay the same within 
                        // a request because we do reference comparisons.  Note the provider can return 
                        // different metadata instances within the same request.  The the Validate*() methods
                        // will make sure to return the first cached instance. 
                        ResourceType type = this.ValidateResourceType(resourceType);
                        if (type != null)
                        {
                            yield return type; 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// Returns all the visible service operations in this data source.
        /// WARNING!!! This property can only be called for the $metadata path because it enumerates through all service operations. 
        /// Calling it from outside of the $metadata path would break our IDSP contract.
        ///  
        public IEnumerable ServiceOperations 
        {
            get 
            {
                var serviceOperations = this.metadataProvider.ServiceOperations;
                if (serviceOperations != null)
                { 
                    HashSet serviceOperationNames = new HashSet(EqualityComparer.Default);
 
                    foreach (ServiceOperation serviceOperation in serviceOperations) 
                    {
                        // verify that the name of the service operation is unique 
                        AddUniqueNameToSet(
                            serviceOperation != null ? serviceOperation.Name : null,
                            serviceOperationNames,
                            Strings.DataServiceProviderWrapper_MultipleServiceOperationsWithSameName(serviceOperation.Name)); 

                        // For IDSP, we want to make sure the metadata object instance stay the same within 
                        // a request because we do reference comparisons.  Note the provider can return 
                        // different metadata instances within the same request.  The the Validate*() methods
                        // will make sure to return the first cached instance. 
                        ServiceOperationWrapper serviceOperationWrapper = this.ValidateServiceOperation(serviceOperation);
                        if (serviceOperationWrapper != null)
                        {
                            yield return serviceOperationWrapper; 
                        }
                    } 
                } 
            }
        } 

        #endregion IDataServiceMetadataProvider Properties

        #region Properties 

        ///  
        /// Cached configuration with access rights info. 
        /// 
        internal DataServiceConfiguration Configuration 
        {
            [DebuggerStepThrough]
            get { return this.metadata.Configuration; }
        } 

#if DEBUG 
        ///  
        /// Used for verifying expression generated for queries, checks if all the
        ///  
        internal bool AreAllResourceTypesNonOpen
        {
            get
            { 
                return !this.VisibleTypeCache.Values.Any(rt => rt.IsOpenType);
            } 
        } 
#endif
 
        /// 
        /// Returns true if the data provider is a V1 provider i.e. ReflectionServiceProvider or ObjectContextServiceProvider.
        /// Otherwise returns false.
        ///  
        internal bool IsV1Provider
        { 
            get { return this.metadataProvider is BaseServiceProvider; } 
        }
 
        /// 
        /// Returns the  for this provider
        /// 
        /// The  for this provider 
        /// Note that this will only return non-null on V1 providers
        /// in which case it returns our V1 provider's implementation of this interface. 
        /// In all other cases this returns null as we don't allow custom implementation of this interface yet. 
        internal IProjectionProvider ProjectionProvider
        { 
            get
            {
                if (this.IsV1Provider)
                { 
                    return (IProjectionProvider)this.metadataProvider;
                } 
                else 
                {
                    return null; 
                }
            }
        }
 
        /// 
        /// Keep track of the calculated visibility of resource types. 
        ///  
        private Dictionary VisibleTypeCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.VisibleTypeCache; }
        }
 
        /// 
        /// Maps resource set names to ResourceSetWrappers. 
        ///  
        private Dictionary ResourceSetWrapperCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ResourceSetWrapperCache; }
        }
 
        /// 
        /// Maps service operation names to ServiceOperationWrappers. 
        ///  
        private Dictionary ServiceOperationWrapperCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ServiceOperationWrapperCache; }
        }
 
        /// 
        /// Maps names to ResourceAssociationSets. 
        ///  
        private Dictionary ResourceAssociationSetCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ResourceAssociationSetCache; }
        }
 
        /// 
        /// Mapes "resourceSetName_resourceTypeName" to the list of visible properties from the set. 
        ///  
        private Dictionary> ResourcePropertyCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ResourcePropertyCache; }
        }
 
        /// 
        /// Mapes "resourceSetName_resourceTypeName" to boolean of whether resourceType is allowed for resourceSet 
        ///  
        private Dictionary EntityTypeDisallowedForSet
        { 
            [DebuggerStepThrough]
            get { return this.metadata.EntityTypeDisallowedForSet; }
        }
 
        #endregion Properties
 
        #region IDataServiceQueryProvider Methods 

#if DEBUG 
        /// 
        /// Returns the IQueryable that represents the container.
        /// 
        /// resource set representing the entity set. 
        /// 
        /// An IQueryable that represents the container; null if there is 
        /// no container for the specified name. 
        /// 
        public IQueryable GetQueryRootForResourceSet(ResourceSetWrapper resourceSet, IDataService dataService) 
#else
        /// 
        /// Returns the IQueryable that represents the container.
        ///  
        /// resource set representing the entity set.
        ///  
        /// An IQueryable that represents the container; null if there is 
        /// no container for the specified name.
        ///  
        public IQueryable GetQueryRootForResourceSet(ResourceSetWrapper resourceSet)
#endif
        {
            Debug.Assert(resourceSet != null, "resourceSet != null"); 
#if DEBUG
            dataService.ProcessingPipeline.AssertDebugStateDuringRequestProcessing(dataService); 
#endif 
            return this.queryProvider.GetQueryRootForResourceSet(resourceSet.ResourceSet);
        } 

        /// Gets the  for the specified .
        /// Instance to extract a  from.
        /// The  that describes this  in this provider. 
        public ResourceType GetResourceType(object instance)
        { 
            Debug.Assert(instance != null, "instance != null"); 
            return this.ValidateResourceType(this.queryProvider.GetResourceType(instance));
        } 

        /// 
        /// Get the value of the strongly typed property.
        ///  
        /// instance of the type declaring the property.
        /// resource property describing the property. 
        /// Resource type to which the property belongs. 
        /// value for the property.
        public object GetPropertyValue(object target, ResourceProperty resourceProperty, ResourceType resourceType) 
        {
            Debug.Assert(target != null, "target != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
            Debug.Assert(resourceProperty.IsReadOnly, "resourceProperty.IsReadOnly"); 
            if (resourceProperty.CanReflectOnInstanceTypeProperty)
            { 
                try 
                {
                    if (resourceType == null) 
                    {
                        resourceType = this.GetResourceType(target);
                    }
 
                    Debug.Assert(resourceType != null, "resourceType != null");
                    PropertyInfo propertyInfo = resourceType.GetPropertyInfo(resourceProperty); 
                    Debug.Assert(propertyInfo != null, "propertyInfo != null"); 
                    return propertyInfo.GetGetMethod().Invoke(target, null);
                } 
                catch (TargetInvocationException exception)
                {
                    ErrorHandler.HandleTargetInvocationException(exception);
                    throw; 
                }
            } 
            else 
            {
                return this.queryProvider.GetPropertyValue(target, resourceProperty); 
            }
        }

        ///  
        /// Get the value of the open property.
        ///  
        /// instance of the type declaring the open property. 
        /// name of the open property.
        /// value for the open property. 
        public object GetOpenPropertyValue(object target, string propertyName)
        {
            Debug.Assert(target != null, "target != null");
            Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); 
            return this.queryProvider.GetOpenPropertyValue(target, propertyName);
        } 
 
        /// 
        /// Get the name and values of all the properties defined in the given instance of an open type. 
        /// 
        /// instance of a open type.
        /// collection of name and values of all the open properties.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "need to return a collection of key value pair")] 
        public IEnumerable> GetOpenPropertyValues(object target)
        { 
            Debug.Assert(target != null, "target != null"); 
            IEnumerable> result = this.queryProvider.GetOpenPropertyValues(target);
            if (result == null) 
            {
                return EmptyOpenPropertyValues;
            }
 
            return result;
        } 
 
        /// 
        /// Invoke the given service operation and returns the results. 
        /// 
        /// service operation to invoke.
        /// value of parameters to pass to the service operation.
        /// returns the result of the service operation. If the service operation returns void, then this should return null. 
        public object InvokeServiceOperation(ServiceOperationWrapper serviceOperation, object[] parameters)
        { 
            Debug.Assert(serviceOperation != null, "serviceOperation != null"); 
            return this.queryProvider.InvokeServiceOperation(serviceOperation.ServiceOperation, parameters);
        } 

        #endregion IDataServiceQueryProvider Methods

        #region IDataServiceMetadataProvider Methods 

        /// Given the specified name, tries to find a resource set. 
        /// Name of the resource set to resolve. 
        /// Resolved resource set, possibly null.
        public ResourceSetWrapper TryResolveResourceSet(string name) 
        {
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");

            // For IDSP, we want to make sure the metadata object instance stay the same within 
            // a request because we do reference comparisons.
            ResourceSetWrapper resourceSetWrapper; 
            if (this.ResourceSetWrapperCache.TryGetValue(name, out resourceSetWrapper)) 
            {
                return resourceSetWrapper; 
            }

            ResourceSet resourceSet;
            if (this.metadataProvider.TryResolveResourceSet(name, out resourceSet)) 
            {
                return this.ValidateResourceSet(resourceSet); 
            } 

            return null; 
        }

        /// 
        /// Gets the ResourceAssociationSet instance when given the source association end. 
        /// 
        /// Resource set of the source association end. 
        /// Resource type of the source association end. 
        /// Resource property of the source association end.
        /// ResourceAssociationSet instance. 
        public ResourceAssociationSet GetResourceAssociationSet(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(resourceProperty != null, "resourceProperty != null");
 
            // If the association set has already been cached, use the cached copy 
            resourceType = GetDeclaringTypeForProperty(resourceType, resourceProperty);
            string associationSetKey = resourceSet.Name + '_' + resourceType.FullName + '_' + resourceProperty.Name; 
            ResourceAssociationSet associationSet;
            if (this.ResourceAssociationSetCache.TryGetValue(associationSetKey, out associationSet))
            {
                return associationSet; 
            }
 
            // Get the association set from the underlying provider. 
            associationSet = this.metadataProvider.GetResourceAssociationSet(resourceSet.ResourceSet, resourceType, resourceProperty);
            if (associationSet != null) 
            {
                ResourceAssociationSetEnd thisEnd = associationSet.GetResourceAssociationSetEnd(resourceSet, resourceType, resourceProperty);
                ResourceAssociationSetEnd relatedEnd = associationSet.GetRelatedResourceAssociationSetEnd(resourceSet, resourceType, resourceProperty);
                ResourceSetWrapper relatedSet = this.ValidateResourceSet(relatedEnd.ResourceSet); 
                if (relatedSet == null)
                { 
                    // If the related set is not visible, the association set is also not visible. 
                    associationSet = null;
                } 
                else
                {
                    ResourceType relatedType = this.ValidateResourceType(relatedEnd.ResourceType);
                    ResourceProperty relatedProperty = null; 
                    if (relatedEnd.ResourceProperty != null)
                    { 
                        relatedProperty = relatedType.TryResolvePropertyName(relatedEnd.ResourceProperty.Name); 
                    }
 
                    // For IDSP, we want to make sure the metadata object instance stay the same within a request because we
                    // do reference comparisons.  Note if the provider returns a ResourceAssociationSet with different instances
                    // of ResourceSet, ResourceType and ResourceProperty than what we've seen earlier in the same request, we
                    // create a new instance of the association set using the metadata objects we've already cached. 
                    // If the metadata change should cause a failure, we want the IDSP to detect it and fail. At the Astoria runtime
                    // layer we assume the metadata objects to remain constant throughout the request. 
                    resourceType = this.ValidateResourceType(thisEnd.ResourceType); 
                    if (thisEnd.ResourceSet != resourceSet.ResourceSet ||
                        thisEnd.ResourceType != resourceType || 
                        thisEnd.ResourceProperty != resourceProperty ||
                        relatedEnd.ResourceSet != relatedSet.ResourceSet ||
                        relatedEnd.ResourceType != relatedType ||
                        relatedEnd.ResourceProperty != relatedProperty) 
                    {
                        associationSet = new ResourceAssociationSet( 
                            associationSet.Name, 
                            new ResourceAssociationSetEnd(resourceSet.ResourceSet, resourceType, resourceProperty),
                            new ResourceAssociationSetEnd(relatedSet.ResourceSet, relatedType, relatedProperty)); 
                    }
                }
            }
 
            this.ResourceAssociationSetCache.Add(associationSetKey, associationSet);
            return associationSet; 
        } 

        /// Given the specified name, tries to find a type. 
        /// Name of the type to resolve.
        /// Resolved resource type, possibly null.
        public ResourceType TryResolveResourceType(string name)
        { 
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");
 
            // For IDSP, we want to make sure the metadata object instance stay the same within 
            // a request because we do reference comparisons.
            ResourceType resourceType; 
            if (this.VisibleTypeCache.TryGetValue(name, out resourceType))
            {
                return resourceType;
            } 

            if (this.metadataProvider.TryResolveResourceType(name, out resourceType)) 
            { 
                return this.ValidateResourceType(resourceType);
            } 

            return null;
        }
 
        /// 
        /// The method must return a collection of all the types derived from . 
        /// The collection returned should NOT include the type passed in as a parameter. 
        /// An implementer of the interface should return null if the type does not have any derived types (ie. null == no derived types).
        ///  
        /// Resource to get derived resource types from.
        /// 
        /// A collection of resource types () derived from the specified 
        /// or null if there no types derived from the specified  exist. 
        /// 
        public IEnumerable GetDerivedTypes(ResourceType resourceType) 
        { 
            Debug.Assert(resourceType != null, "resourceType != null");
 
            var derivedTypes = this.metadataProvider.GetDerivedTypes(resourceType);
            if (derivedTypes != null)
            {
                foreach (ResourceType derivedType in derivedTypes) 
                {
                    ResourceType type = this.ValidateResourceType(derivedType); 
                    if (type != null) 
                    {
                        yield return type; 
                    }
                }
            }
        } 

        ///  
        /// Returns true if  represents an Entity Type which has derived Entity Types, else false. 
        /// 
        /// instance of the resource type in question. 
        /// True if  represents an Entity Type which has derived Entity Types, else false.
        public bool HasDerivedTypes(ResourceType resourceType)
        {
            Debug.Assert(this.ValidateResourceType(resourceType) != null, "resourceType must be read-only and visible."); 
            return this.metadataProvider.HasDerivedTypes(resourceType);
        } 
 
        /// Given the specified name, tries to find a service operation.
        /// Name of the service operation to resolve. 
        /// Resolved service operation, possibly null.
        public ServiceOperationWrapper TryResolveServiceOperation(string name)
        {
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)"); 

            // For IDSP, we want to make sure the metadata object instance stay the same within 
            // a request because we do reference comparisons. 
            ServiceOperationWrapper serviceOperationWrapper;
            if (this.ServiceOperationWrapperCache.TryGetValue(name, out serviceOperationWrapper)) 
            {
                return serviceOperationWrapper;
            }
 
            ServiceOperation serviceOperation;
            if (this.metadataProvider.TryResolveServiceOperation(name, out serviceOperation)) 
            { 
                return this.ValidateServiceOperation(serviceOperation);
            } 

            return null;
        }
 
        #endregion IDataServiceMetadataProvider Methods
 
        #region Internal Methods 

        ///  
        /// Gets the resource type which the resource property is declared on.
        /// 
        /// resource type to start looking
        /// resource property in question 
        /// actual resource type that declares the property
        internal static ResourceType GetDeclaringTypeForProperty(ResourceType resourceType, ResourceProperty resourceProperty) 
        { 
            Debug.Assert(resourceType != null, "resourceType != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 

            while (resourceType != null)
            {
                if (resourceType.TryResolvePropertiesDeclaredOnThisTypeByName(resourceProperty.Name) != null) 
                {
                    break; 
                } 

                resourceType = resourceType.BaseType; 
            }

            Debug.Assert(resourceType != null, "resourceType != null");
            return resourceType; 
        }
 
        /// Disposes of the metadata and query providers. 
        internal void DisposeDataSource()
        { 
            Debug.Assert(this.queryProvider != null, "this.queryProvider != null");
            Debug.Assert(this.metadataProvider != null, "this.metadataProvider != null");

            WebUtil.Dispose(this.metadataProvider); 

            // If the same instance implements IDataServiceMetadataProvider and IDataServiceQueryProvider interface, 
            // we call dispose only once. 
            if (this.metadataProvider != this.queryProvider)
            { 
                WebUtil.Dispose(this.queryProvider);
            }

            this.metadataProvider = null; 
            this.queryProvider = null;
        } 
 
        /// 
        /// Iterates through the resource sets, service operations and resource types to pre-populate the metadata cache item. 
        /// 
        internal void PopulateMetadataCacheItemForV1Provider()
        {
            Debug.Assert(this.IsV1Provider, "this.IsV1Provider"); 

            // This is only called when we initialize the service for the first time. 
            // The Count extention method will cause the iterator to instantiate the wrapper classes. 
            this.ServiceOperations.Count();
            this.Types.Count(); 

            foreach (ResourceSetWrapper resourceSet in this.ResourceSets)
            {
                // Derived types of a visible type are visible 
                foreach (ResourceType derivedType in this.GetDerivedTypes(resourceSet.ResourceType))
                { 
                    this.GetResourceProperties(resourceSet, derivedType); 
                    this.IsEntityTypeDisallowedForSet(resourceSet, derivedType);
                } 

                // Base types of a visible type are visible
                ResourceType resourceType = resourceSet.ResourceType;
                while (resourceType != null) 
                {
                    this.GetResourceProperties(resourceSet, resourceType); 
                    this.IsEntityTypeDisallowedForSet(resourceSet, resourceType); 
                    resourceType = resourceType.BaseType;
                } 
            }
        }

        ///  
        /// Gets the target container for the given navigation property, source container and the source resource type
        ///  
        /// source entity set. 
        /// source resource type.
        /// navigation property. 
        /// target container that the navigation property refers to.
        internal ResourceSetWrapper GetContainer(ResourceSetWrapper sourceContainer, ResourceType sourceResourceType, ResourceProperty navigationProperty)
        {
            ResourceAssociationSet associationSet = this.GetResourceAssociationSet(sourceContainer, sourceResourceType, navigationProperty); 
            if (associationSet != null)
            { 
                ResourceAssociationSetEnd relatedEnd = associationSet.GetRelatedResourceAssociationSetEnd(sourceContainer, sourceResourceType, navigationProperty); 
                return this.ValidateResourceSet(relatedEnd.ResourceSet);
            } 

            return null;
        }
 
        /// 
        /// For a V1 provider checks the Epm compatiblity in order to write the appropriate 
        /// versioning header for metadata requests 
        /// 
        /// true if the provider is V1 compatible, false otherwise 
        internal bool GetEpmCompatiblityForV1Provider()
        {
            Debug.Assert(this.IsV1Provider, "Must be a V1 provider to call this function");
            return (this.metadataProvider as BaseServiceProvider).EpmIsV1Compatible; 
        }
 
        ///  
        /// Return the list of ETag properties for a given type in the context of a given container
        ///  
        /// Name of the container to use for context (for MEST-enabled providers)
        /// Type to get the ETag properties for
        /// A collection of the properties that form the ETag for the given type in the given container
        internal IList GetETagProperties(string containerName, ResourceType resourceType) 
        {
            Debug.Assert(containerName != null || !(this.metadataProvider is ObjectContextServiceProvider), "ContainerName is required for MEST-enabled provider (EFx provider)"); 
            Debug.Assert(resourceType != null && resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Resource should be non-null and of an entity type"); 

            // Note only primitive properties can be part of an etag, they are always visible. 
            ObjectContextServiceProvider efxProvider = this.metadataProvider as ObjectContextServiceProvider;
            return efxProvider == null ? resourceType.ETagProperties :
                                         efxProvider.GetETagProperties(containerName, resourceType);
        } 

        ///  
        /// Gets the visible resource properties for  from . 
        /// We cache the list of visible resource properties so we don't have to calculate it repeatedly when serializing feeds.
        ///  
        /// Resource set in question.
        /// Resource type in question.
        /// List of visible resource properties from the given resource set and resource type.
        internal IEnumerable GetResourceProperties(ResourceSetWrapper resourceSet, ResourceType resourceType) 
        {
            Debug.Assert(resourceType != null, "resourceType != null"); 
            if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) 
            {
                Debug.Assert(resourceSet != null, "resourceSet != null"); 
                string key = resourceSet.Name + '_' + resourceType.FullName;
                List properties;
                if (!this.ResourcePropertyCache.TryGetValue(key, out properties))
                { 
                    properties = new List();
                    foreach (ResourceProperty property in resourceType.Properties) 
                    { 
                        if (property.TypeKind == ResourceTypeKind.EntityType && this.GetContainer(resourceSet, resourceType, property) == null)
                        { 
                            continue;
                        }

                        properties.Add(property); 
                    }
 
                    this.ResourcePropertyCache.Add(key, properties); 
                }
 
                return properties;
            }
            else
            { 
                return resourceType.Properties;
            } 
        } 

        ///  
        /// Write the metadata document.
        /// 
        /// instance of the metadata serializer.
        /// xml writer in which we need to write the metadata document. 
        /// Data service instance.
        internal void WriteMetadataDocument(MetadataSerializer serializer, XmlWriter writer, IDataService service) 
        { 
            Debug.Assert(serializer != null, "serializer != null");
            Debug.Assert(writer != null, "writer != null"); 

            BaseServiceProvider internalProvider = this.metadataProvider as BaseServiceProvider;
            ObjectContextServiceProvider efxProvider = this.metadataProvider as ObjectContextServiceProvider;
 
            // always v1.1+ schemas for custom providers
            MetadataEdmSchemaVersion metadataEdmSchemaVersion = internalProvider == null ? MetadataEdmSchemaVersion.Version1Dot1 : internalProvider.EdmSchemaVersion; 
 
            if (efxProvider == null)
            { 
                serializer.GenerateMetadata(metadataEdmSchemaVersion, service);
            }
            else
            { 
                efxProvider.GetMetadata(writer, this, service);
            } 
        } 

        ///  
        /// Check if the given type can be ordered. If not, throw an exception.
        /// 
        /// clr type which needs to checked for ordering.
        internal void CheckIfOrderedType(Type clrType) 
        {
            // For known providers check for sort-ability for better error reporting 
            BaseServiceProvider baseProvider = this.metadataProvider as BaseServiceProvider; 
            if (baseProvider != null &&
                !baseProvider.GetTypeIsOrdered(clrType)) 
            {
                string resourceTypeName = WebUtil.GetTypeName(clrType);
                throw DataServiceException.CreateBadRequestError(Strings.RequestQueryParser_OrderByDoesNotSupportType(resourceTypeName));
            } 
        }
 
        ///  
        /// Checks whether the current data provider is a V1 provider or not.
        ///  
        /// Returns true if the current data source is a V1 provider. Otherwise, returns false.
        internal bool IsV1ProviderAndImplementsUpdatable()
        {
            BaseServiceProvider baseServiceProvider = this.metadataProvider as BaseServiceProvider; 
            if (baseServiceProvider != null &&
                baseServiceProvider.ImplementsIUpdatable()) 
            { 
                return true;
            } 

            return false;
        }
 
        /// 
        /// Retrieve an implementation of a data service interface (ie. IUpdatable, IExpandProvider,etc) 
        ///  
        /// The type representing the requested interface
        /// Data service instance 
        /// An object implementing the requested interface, or null if not available
        internal T GetService(IDataService dataService) where T : class
        {
            Debug.Assert(dataService != null, "dataService != null"); 
            Debug.Assert(dataService.Provider == this, "dataService.Provider == this");
            Debug.Assert(typeof(T) != typeof(IDataServiceMetadataProvider), "typeof(T) != typeof(IDataServiceMetadataProvider)"); 
            Debug.Assert(typeof(T) != typeof(IDataServiceQueryProvider), "typeof(T) != typeof(IDataServiceQueryProvider)"); 
            Debug.Assert(typeof(T).IsVisible, "Trying to ask the service for non-public interface.");
 
#if DEBUG
            dataService.ProcessingPipeline.AssertDebugStateDuringRequestProcessing(dataService);
            dataService.ProcessingPipeline.HasInstantiatedProviderInterfaces = true;
#endif 
            // *NOTE* to limit test surface area, IDataServiceStreamProvider && IExpandProvider are the only custom implementation
            // we support for ObjectContextServiceProvider. 
            // Should remove this in the future. 
            if (this.metadataProvider is ObjectContextServiceProvider && typeof(T) != typeof(IDataServiceStreamProvider) && typeof(T) != typeof(IExpandProvider))
            { 
                // Return internal implementation of the interface if there is one.
                return WebUtil.GetService(this.metadataProvider);
            }
 
            // 1. Check if subclass of DataService implements IServiceProvider. If it does, then call IServiceProvider.GetService()
            // with the appropriate type. If it doesn’t proceed to Step 2 
            //    a. If IServiceProvider.GetService() returns something, then go ahead and use that instance 
            //    b. If IServiceProvider.GetService() doesn't return anything, proceed to Step 2.
            T result = WebUtil.GetService(dataService.Instance); 
            if (result != null)
            {
                return result;
            } 

            // 2. Check if the T (where T is the type from DataService) implements the interface. 
            //    a. If yes, use that. 
            //    b. If no, proceed to Step 3
            result = this.CurrentDataSource as T; 
            if (result != null)
            {
                // Since IDataServiceUpdateProvider derives from IUpdatable, we need to make sure that
                // when asked for IUpdatable, this method checks only for IUpdatable, and returns null 
                // if the type returns IDataServiceUpdateProvider.
                if (typeof(T) != typeof(IUpdatable) || ((result as IDataServiceUpdateProvider) == null)) 
                { 
                    return result;
                } 
            }

            // 3. Check if the data service provider is a V1 provider
            //    a. If yes, return an internal implementation if we can find one. 
            //    b. If no, then the provider doesn’t support the current interface functionality.
            if (this.IsV1Provider) 
            { 
                // Look for internal implementation for the interface
                return WebUtil.GetService(this.metadataProvider); 
            }

            return null;
        } 

        ///  
        /// We do not allow entity sets to contain any derived type with navigation properties in the GET path 
        /// 
        /// entity set containing the resource type. 
        /// entity type in the hierarchy returned by .
        /// True if the derived type has any navigation properties.
        internal bool IsEntityTypeDisallowedForSet(ResourceSetWrapper resourceSet, ResourceType resourceType)
        { 
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null"); 
 
            object result;
            string key = resourceSet.Name + '_' + resourceType.FullName; 
            if (this.EntityTypeDisallowedForSet.TryGetValue(key, out result))
            {
                Debug.Assert(result == DataServiceProviderWrapper.RefTrue || result == DataServiceProviderWrapper.RefFalse, "result must be either RefTrue or RefFalse.");
                return result == DataServiceProviderWrapper.RefTrue ? true : false; 
            }
 
            ResourceType baseType = resourceSet.ResourceType; 
            if (baseType != resourceType && baseType.IsAssignableFrom(resourceType) && this.HasNavigationProperties(resourceSet, resourceType))
            { 
                this.EntityTypeDisallowedForSet.Add(key, DataServiceProviderWrapper.RefTrue);
                return true;
            }
            else 
            {
                this.EntityTypeDisallowedForSet.Add(key, DataServiceProviderWrapper.RefFalse); 
                return false; 
            }
        } 

        /// 
        /// Validates if the container should be visible and is not read only. If the container rights
        /// are set to None the container should not be visible. 
        /// 
        /// Resource set to be validated. 
        /// Validated container, null if the container is not supposed to be visible. 
        internal ResourceSetWrapper ValidateResourceSet(ResourceSet resourceSet)
        { 
            ResourceSetWrapper resourceSetWrapper = null;
            if (resourceSet != null)
            {
                // For IDSP, we want to make sure the metadata object instance stay the same within 
                // a request because we do reference comparisons.  Note the provider can return
                // different metadata instances within the same request.  The the Validate*() methods 
                // will make sure to return the first cached instance. 
                if (this.ResourceSetWrapperCache.TryGetValue(resourceSet.Name, out resourceSetWrapper))
                { 
                    return resourceSetWrapper;
                }

                resourceSetWrapper = new ResourceSetWrapper(resourceSet, this.ValidateResourceType(resourceSet.ResourceType)); 
                resourceSetWrapper.ApplyConfiguration(this.Configuration);
                if (!resourceSetWrapper.IsVisible) 
                { 
                    resourceSetWrapper = null;
                } 

                this.ResourceSetWrapperCache[resourceSet.Name] = resourceSetWrapper;
            }
 
            return resourceSetWrapper;
        } 
 
        #endregion Internal Methods
 
        #region Private Methods

        /// 
        /// Throws if resource type is not sealed. 
        /// 
        /// resource type to inspect. 
        private static void ValidateResourceTypeReadOnly(ResourceType resourceType) 
        {
            Debug.Assert(resourceType != null, "resourceType != null"); 
            if (!resourceType.IsReadOnly)
            {
                throw new DataServiceException(500, Strings.DataServiceProviderWrapper_ResourceTypeNotReadonly(resourceType.FullName));
            } 
        }
 
        ///  
        /// This is a common method for checking uniqe names across entity sets, resource types and service operations.
        ///  
        /// Name to be added to set.
        /// Set containing already verified names.
        /// String for exception to be thrown if the name is not unique.
        private static void AddUniqueNameToSet(string name, HashSet names, string exceptionString) 
        {
            if (name != null) 
            { 
                if (names.Contains(name))
                { 
                    throw new DataServiceException(500, exceptionString);
                }

                names.Add(name); 
            }
        } 
 
        /// Validates that  is cached and read only.
        /// Resource type to be validated. 
        /// Validated resource type, null if the resource type is not supposed to be visible.
        private ResourceType ValidateResourceType(ResourceType resourceType)
        {
            if (resourceType != null) 
            {
                // For IDSP, we want to make sure the metadata object instance stay the same within 
                // a request because we do reference comparisons.  Note the provider can return 
                // different metadata instances within the same request.  The the Validate*() methods
                // will make sure to return the first cached instance. 
                ResourceType cachedType;
                if (this.VisibleTypeCache.TryGetValue(resourceType.FullName, out cachedType))
                {
                    return cachedType; 
                }
 
                ValidateResourceTypeReadOnly(resourceType); 
                this.VisibleTypeCache[resourceType.FullName] = resourceType;
                return resourceType; 
            }

            return null;
        } 

        ///  
        /// Validates if the service operation should be visible and is read only. If the service operation 
        /// rights are set to None the service operation should not be visible.
        ///  
        /// Service operation to be validated.
        /// Validated service operation, null if the service operation is not supposed to be visible.
        private ServiceOperationWrapper ValidateServiceOperation(ServiceOperation serviceOperation)
        { 
            ServiceOperationWrapper serviceOperationWrapper = null;
            if (serviceOperation != null) 
            { 
                // For IDSP, we want to make sure the metadata object instance stay the same within
                // a request because we do reference comparisons.  Note the provider can return 
                // different metadata instances within the same request.  The the Validate*() methods
                // will make sure to return the first cached instance.
                if (this.ServiceOperationWrapperCache.TryGetValue(serviceOperation.Name, out serviceOperationWrapper))
                { 
                    return serviceOperationWrapper;
                } 
 
                serviceOperationWrapper = new ServiceOperationWrapper(serviceOperation);
                serviceOperationWrapper.ApplyConfiguration(this.Configuration, this); 
                if (!serviceOperationWrapper.IsVisible)
                {
                    serviceOperationWrapper = null;
                } 

                this.ServiceOperationWrapperCache[serviceOperation.Name] = serviceOperationWrapper; 
            } 

            return serviceOperationWrapper; 
        }

        /// 
        /// Checks whether the resource type from the resource set has visible navigation properties or not. 
        /// 
        /// resource set instance to inspect. 
        /// resource type to inspect. 
        /// Returns true if the resource type has one or more visible navigation properties from the resource set. Otherwise returns false.
        private bool HasNavigationProperties(ResourceSetWrapper resourceSet, ResourceType resourceType) 
        {
            foreach (ResourceProperty property in resourceType.PropertiesDeclaredOnThisType)
            {
                if (property.TypeKind != ResourceTypeKind.EntityType) 
                {
                    continue; 
                } 

                if (this.GetResourceAssociationSet(resourceSet, resourceType, property) != null) 
                {
                    return true;
                }
            } 

            return false; 
        } 

        #endregion Private Methods 
    }
}

// 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