BaseServiceProvider.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 / BaseServiceProvider.cs / 1305376 / BaseServiceProvider.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Abstract Class which contains the common code for ObjectContextServiceProvider
//      and ReflectionServiceProvider 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Data.Services.Caching;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq; 
    using System.Reflection;
    using System.ServiceModel.Web; 
 
    #endregion Namespaces.
 
    /// Provides a reflection-based provider implementation.
    internal abstract class BaseServiceProvider : IDataServiceMetadataProvider, IDataServiceQueryProvider, IDisposable, IProjectionProvider, IServiceProvider
    {
        /// Bindings Flags to be used for reflection. 
        protected const BindingFlags ResourceContainerBindingFlags = WebUtil.PublicInstanceBindingFlags;
 
        /// Instance from which data is provided. 
        private object instance;
 
        /// Metadata to be used by the service provider.
        private MetadataCacheItem metadata;

        /// instance of the service to invoke service operations. 
        private object dataServiceInstance;
 
        ///  
        /// Reference back to the provider wrapper.
        ///  
        private DataServiceProviderWrapper providerWrapper;

        /// 
        /// Initializes a new System.Data.Services.BaseServiceProvider instance. 
        /// 
        /// Metadata for this provider. 
        /// data service instance. 
        protected BaseServiceProvider(MetadataCacheItem metadata, object dataServiceInstance)
        { 
            WebUtil.CheckArgumentNull(metadata, "metadata");
            WebUtil.CheckArgumentNull(dataServiceInstance, "dataServiceInstance");
            this.metadata = metadata;
            this.dataServiceInstance = dataServiceInstance; 
        }
 
        #region IDataServiceQueryProvider Properties 

        /// Returns the instance from which data is provided. 
        public object CurrentDataSource
        {
            [DebuggerStepThrough]
            get 
            {
                // Many debuggers will try to display this property, and we don't want to trigger an assertion. 
                Debug.Assert( 
                    System.Diagnostics.Debugger.IsAttached || this.instance != null,
                    "this.instance != null -- otherwise CurrentDataSource is accessed before initialization or after disposal."); 
                return this.instance;
            }

            set 
            {
                WebUtil.CheckArgumentNull(value, "value"); 
                this.instance = value; 
            }
        } 

        /// Gets a value indicating whether null propagation is required in expression trees.
        public abstract bool IsNullPropagationRequired
        { 
            get;
        } 
 
        #endregion IDataServiceQueryProvider Properties
 
        #region IDataServiceMetadataProvider Properties

        /// Namespace name for the EDM container.
        public abstract string ContainerNamespace 
        {
            get; 
        } 

        /// Name of the EDM container 
        public abstract string ContainerName
        {
            get;
        } 

        /// Gets all available containers. 
        /// An enumerable object with all available containers. 
        public IEnumerable ResourceSets
        { 
            get { return this.EntitySets.Values; }
        }

        /// Returns all the types in this data source 
        public IEnumerable Types
        { 
            get { return this.metadata.TypeCache.Values; } 
        }
 
        /// Returns all known service operations.
        public IEnumerable ServiceOperations
        {
            get 
            {
                foreach (ServiceOperation serviceOperation in this.metadata.ServiceOperations.Values) 
                { 
                    yield return serviceOperation;
                } 
            }
        }

        #endregion IDataServiceMetadataProvider Properties 

        /// EDM version to which metadata is compatible. 
        ///  
        /// For example, a service operation of type Void is not acceptable 1.0 CSDL,
        /// so it should use 1.1 CSDL instead. Similarly, OpenTypes are supported 
        /// in 1.2 and not before.
        /// 
        internal MetadataEdmSchemaVersion EdmSchemaVersion
        { 
            get { return this.metadata.EdmSchemaVersion; }
        } 
 
        /// Whether all EPM properties serialize in an Astoria V1-compatible way.
        ///  
        /// This property is false if any property has KeepInContent set to false.
        /// 
        internal bool EpmIsV1Compatible
        { 
            [DebuggerStepThrough]
            get { return this.metadata.EpmIsV1Compatible; } 
        } 

        ///  
        /// Reference back to the provider wrapper.
        /// 
        internal DataServiceProviderWrapper ProviderWrapper
        { 
            set
            { 
                this.providerWrapper = value; 
            }
 
            get
            {
                Debug.Assert(this.providerWrapper != null, "this.providerWrapper != null");
                return this.providerWrapper; 
            }
        } 
 
        /// Returns the list of entity sets.
        protected IDictionary EntitySets 
        {
            [DebuggerStepThrough]
            get { return this.metadata.EntitySets; }
        } 

        /// Target type for the data provider  
        protected Type Type 
        {
            [DebuggerStepThrough] 
            get { return this.metadata.Type; }
        }

        /// Cache of resource properties per type. 
        private Dictionary TypeCache
        { 
            [DebuggerStepThrough] 
            get { return this.metadata.TypeCache; }
        } 

        /// Cache of immediate derived types per type.
        private Dictionary> ChildTypesCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ChildTypesCache; } 
        } 

        #region Public Methods 

        /// Applies expansions and projections to the specified .
        ///  object to expand and apply projections to.
        /// The root node of the tree which describes 
        /// the projections and expansions to be applied to the .
        ///  
        /// An  object, with the results including 
        /// the expansions and projections specified in .
        ///  
        /// 
        /// The returned  may implement the  interface
        /// to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects. If paging is 
        /// requested by providing a non-empty list in .OrderingInfo then
        /// it is expected that the topmost  would have a $skiptoken property 
        /// which will be an  in itself and each of it's sub-properties will 
        /// be named SkipTokenPropertyXX where XX represents numbers in increasing order starting from 0. Each of
        /// SkipTokenPropertyXX properties will be used to generated the $skiptoken to support paging. 
        /// If projections are required, the provider may choose to return 
        /// which returns instances of . In that case property values are determined
        /// by calling the  method instead of
        /// accessing properties of the returned object directly. 
        /// If both expansion and projections are required, the provider may choose to return 
        /// of  which in turn returns  from its 
        ///  property. 
        /// 
        public abstract IQueryable ApplyProjections( 
            IQueryable source,
            ProjectionNode projection);

        ///  
        /// 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 abstract ResourceAssociationSet GetResourceAssociationSet(ResourceSet resourceSet, ResourceType resourceType, ResourceProperty resourceProperty);

        ///  
        /// Checks whether the specified  is ordered.
        ///  
        /// Type to check. 
        /// true if the type may be ordered; false otherwise.
        ///  
        /// The ordering may still fail at runtime; this method is currently
        /// used for cleaner error messages only.
        /// 
        public virtual bool GetTypeIsOrdered(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 
            return type == typeof(object) || WebUtil.IsPrimitiveType(type); 
        }
 
        /// 
        /// Returns the requested service
        /// 
        /// type of service you are requesting for. 
        /// returns the instance of the requested service.
        public virtual object GetService(Type serviceType) 
        { 
            if (typeof(IDataServiceMetadataProvider) == serviceType ||
                typeof(IDataServiceQueryProvider) == serviceType || 
                typeof(IProjectionProvider) == serviceType)
            {
                return this;
            } 

            return null; 
        } 

        /// Releases the current data source object as necessary. 
        void IDisposable.Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this); 
        }
 
        #endregion Public Methods 

        #region IDataServiceQueryProvider Methods 

        /// 
        /// 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(ResourceSet container)
        {
            Debug.Assert(container != null, "resourceContainer != null");
            return this.GetResourceContainerInstance(container); 
        }
 
        /// Gets the  for the specified . 
        /// Instance to extract a  from.
        /// The  that describes this  in this provider. 
        public ResourceType GetResourceType(object resource)
        {
            Debug.Assert(resource != null, "instance != null");
            return this.GetNonPrimitiveType(resource.GetType()); 
        }
 
        ///  
        /// Get the value of the strongly typed property.
        ///  
        /// instance of the type declaring the property.
        /// resource property describing the property.
        /// value for the property.
        public object GetPropertyValue(object target, ResourceProperty resourceProperty) 
        {
            Debug.Assert(target != null, "target != null"); 
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 

            try 
            {
                PropertyInfo propertyInfo = this.GetResourceType(target).GetPropertyInfo(resourceProperty);
                Debug.Assert(propertyInfo != null, "propertyInfo != null");
                return propertyInfo.GetGetMethod().Invoke(target, null); 
            }
            catch (TargetInvocationException exception) 
            { 
                ErrorHandler.HandleTargetInvocationException(exception);
                throw; 
            }
        }

        ///  
        /// Gets the value of the open property.
        ///  
        /// instance of the resource type. 
        /// name of the property.
        /// the value of the open property. If the property is not present, return null. 
        public abstract object GetOpenPropertyValue(object target, string 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. 
        public abstract IEnumerable> GetOpenPropertyValues(object target);
 
        /// 
        /// Invoke the given service operation instance.
        /// 
        /// metadata for the service operation to invoke. 
        /// list of parameters to pass to the service operation.
        /// returns the result by the service operation instance. 
        public object InvokeServiceOperation(ServiceOperation serviceOperation, object[] parameters) 
        {
            return ((MethodInfo)serviceOperation.CustomState).Invoke( 
                    this.dataServiceInstance,
                    BindingFlags.Instance | BindingFlags.Instance | BindingFlags.FlattenHierarchy,
                    null,
                    parameters, 
                    Globalization.CultureInfo.InvariantCulture);
        } 
 
        #endregion IDataServiceQueryProvider Methods
 
        #region IDataServiceMetadataProvider Methods

        /// 
        /// 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"); 
            Debug.Assert(this.ChildTypesCache.ContainsKey(resourceType), "this.ChildTypesCache.ContainsKey(resourceType)"); 

            List childTypes = this.ChildTypesCache[resourceType]; 
            if (childTypes != null)
            {
                foreach (ResourceType childType in childTypes)
                { 
                    yield return childType;
 
                    foreach (ResourceType descendantType in this.GetDerivedTypes(childType)) 
                    {
                        yield return descendantType; 
                    }
                }
            }
        } 

        ///  
        /// 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(resourceType != null, "resourceType != null"); 
            Debug.Assert(this.ChildTypesCache.ContainsKey(resourceType), "this.ChildTypesCache.ContainsKey(resourceType)");
            Debug.Assert(this.ChildTypesCache[resourceType] == null || this.ChildTypesCache[resourceType].Count > 0, "this.ChildTypesCache[resourceType] == null || this.ChildTypesCache[resourceType].Count > 0"); 
 
            return this.ChildTypesCache[resourceType] != null;
        } 

        /// Given the specified name, tries to find a resource set.
        /// Name of the resource set to resolve.
        /// Returns the resolved resource set, null if no resource set for the given name was found. 
        /// True if resource set with the given name was found, false otherwise.
        public bool TryResolveResourceSet(string name, out ResourceSet resourceSet) 
        { 
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");
            return this.EntitySets.TryGetValue(name, out resourceSet); 
        }

        /// Given the specified name, tries to find a service operation.
        /// Name of the service operation to resolve. 
        /// Returns the resolved service operation, null if no service operation was found for the given name.
        /// True if we found the service operation for the given name, false otherwise. 
        public bool TryResolveServiceOperation(string name, out ServiceOperation serviceOperation) 
        {
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)"); 
            return this.metadata.ServiceOperations.TryGetValue(name, out serviceOperation);
        }

        /// Given the specified name, tries to find a type. 
        /// Name of the type to resolve.
        /// Returns the resolved resource type, null if no resource type for the given name was found. 
        /// True if we found the resource type for the given name, false otherwise. 
        public bool TryResolveResourceType(string name, out ResourceType resourceType)
        { 
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");
            Debug.Assert(this.metadata != null, "this.metadata != null");
            Debug.Assert(this.TypeCache != null, "this.TypeCache != null");
            foreach (ResourceType t in this.TypeCache.Values) 
            {
                if (t.FullName == name) 
                { 
                    resourceType = t;
                    return true; 
                }
            }

            resourceType = null; 
            return false;
        } 
 
        #endregion IDataServiceMetadataProvider Methods
 
        #region Internal Methods

        /// 
        /// Returns the type of the IEnumerable if the type implements IEnumerable interface; null otherwise. 
        /// 
        /// type that needs to be checked 
        /// Element type if the type implements IEnumerable, else returns null 
        internal static Type GetIEnumerableElement(Type type)
        { 
            return GetGenericInterfaceElementType(type, IEnumerableTypeFilter);
        }

        ///  
        /// Returns the "T" in the IQueryable of T implementation of type.
        ///  
        /// Type to check. 
        /// filter against which the type is checked
        ///  
        /// The element type for the generic IQueryable interface of the type,
        /// or null if it has none or if it's ambiguous.
        /// 
        internal static Type GetGenericInterfaceElementType(Type type, TypeFilter typeFilter) 
        {
            Debug.Assert(type != null, "type != null"); 
            Debug.Assert(!type.IsGenericTypeDefinition, "!type.IsGenericTypeDefinition"); 

            if (typeFilter(type, null)) 
            {
                return type.GetGenericArguments()[0];
            }
 
            Type[] queriables = type.FindInterfaces(typeFilter, null);
            if (queriables != null && queriables.Length == 1) 
            { 
                return queriables[0].GetGenericArguments()[0];
            } 
            else
            {
                return null;
            } 
        }
 
        ///  
        /// Checks whether the provider implements IUpdatable.
        ///  
        /// returns true if the provider implements IUpdatable. otherwise returns false.
        internal abstract bool ImplementsIUpdatable();

        /// Adds service operations based on methods of the specified type. 
        /// Type with methods to add.
        internal void AddOperationsFromType(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
            foreach (MethodInfo methodInfo in type.GetMethods(WebUtil.PublicInstanceBindingFlags | BindingFlags.FlattenHierarchy)) 
            {
                if (methodInfo.GetCustomAttributes(typeof(WebGetAttribute), true).Length != 0)
                {
                    this.AddServiceOperation(methodInfo, XmlConstants.HttpMethodGet); 
                }
                else if (methodInfo.GetCustomAttributes(typeof(WebInvokeAttribute), true).Length != 0) 
                { 
                    this.AddServiceOperation(methodInfo, XmlConstants.HttpMethodPost);
                } 
            }
        }

        /// Populates the metadata for the given provider. 
        internal void PopulateMetadata()
        { 
            Debug.Assert(this.metadata != null, "this.metadata != null -- otherwise we don't have an item to populate"); 
            this.PopulateMetadata(this.TypeCache, this.ChildTypesCache, this.EntitySets);
        } 

        /// 
        /// Applies access rights to entity sets
        ///  
        /// Data service configuration instance with access right info.
        internal void ApplyConfiguration(DataServiceConfiguration configuration) 
        { 
            Debug.Assert(configuration != null, "configuration != null");
 
            this.PopulateMetadataForUserSpecifiedTypes(configuration.GetKnownTypes(), this.TypeCache, this.ChildTypesCache, this.EntitySets.Values);
            this.CheckConfigurationConsistency(this.instance, configuration);
        }
 
        /// Make all the metadata readonly
        internal void MakeMetadataReadonly() 
        { 
            foreach (ResourceSet container in this.ResourceSets)
            { 
                container.SetReadOnly();
            }

            foreach (ResourceType resourceType in this.Types) 
            {
                resourceType.SetReadOnly(); 
                if (!resourceType.EpmIsV1Compatible) 
                {
                    this.metadata.EpmIsV1Compatible = false; 
                }
            }

            foreach (ServiceOperation operation in this.ServiceOperations) 
            {
                operation.SetReadOnly(); 
            } 
        }
 
        #endregion Internal Methods

        #region Protected methods.
 
        /// 
        /// Returns the type of the IQueryable if the type implements IQueryable interface 
        ///  
        /// clr type on which IQueryable check needs to be performed.
        /// Element type if the property type implements IQueryable, else returns null 
        protected static Type GetIQueryableElement(Type type)
        {
            return GetGenericInterfaceElementType(type, IQueryableTypeFilter);
        } 

        ///  
        /// Find the corresponding ResourceType for a given Type, primitive or not 
        /// 
        /// Non-primitive types to search 
        /// Type to look for
        /// Corresponding ResourceType, if found
        /// True if type found, false otherwise
        protected static bool TryGetType(IDictionary knownTypes, Type type, out ResourceType resourceType) 
        {
            Debug.Assert(knownTypes != null, "knownTypes != null"); 
            Debug.Assert(type != null, "type != null"); 

            resourceType = ResourceType.GetPrimitiveResourceType(type); 

            if (resourceType == null)
            {
                knownTypes.TryGetValue(type, out resourceType); 
            }
 
            return resourceType != null; 
        }
 
        /// Checks that the applied configuration is consistent.
        /// Instance of the data source for the provider.
        /// Data service configuration instance with access right info.
        /// At this point in initialization, metadata trimming hasn't taken place. 
        protected virtual void CheckConfigurationConsistency(object dataSourceInstance, DataServiceConfiguration configuration)
        { 
        } 

        /// Releases the current data source object as necessary. 
        /// 
        /// Whether this method is called from an explicit call to Dispose by
        /// the consumer, rather than during finalization.
        ///  
        protected virtual void Dispose(bool disposing)
        { 
            WebUtil.Dispose(this.instance); 
            this.instance = null;
        } 

        /// 
        /// Returns the resource type of the given instance and validates that the instance returns a single resource.
        ///  
        /// clr instance of a resource.
        /// resource type of the given instance. 
        protected ResourceType GetSingleResource(object resource) 
        {
            ResourceType resourceType = this.ProviderWrapper.GetResourceType(resource); 
            return resourceType;
        }

        ///  
        /// Creates the object query for the given resource set and returns it
        ///  
        /// resource set for which IQueryable instance needs to be created 
        /// returns the IQueryable instance for the given resource set
        protected abstract IQueryable GetResourceContainerInstance(ResourceSet resourceContainer); 

        /// 
        /// Populates the metadata for the given provider
        ///  
        /// list of known types
        /// list of known types and their immediate children 
        /// list of entity sets 
        protected abstract void PopulateMetadata(
            IDictionary knownTypes, 
            IDictionary> childTypes,
            IDictionary entitySets);

        ///  
        /// Populate types for metadata specified by the provider
        ///  
        /// list of types specified by the provider 
        /// list of already known types
        /// list of already known types and their immediate children 
        /// list of entity sets as specified in the data source type
        protected abstract void PopulateMetadataForUserSpecifiedTypes(IEnumerable userSpecifiedTypes, IDictionary knownTypes, IDictionary> childTypes, IEnumerable entitySets);

        ///  
        /// Populate metadata for the given clr type.
        ///  
        /// type whose metadata needs to be loaded. 
        /// list of already known resource types.
        /// list of already known types and their immediate children 
        /// list of entity sets as specified in the data source.
        /// resource type containing metadata for the given clr type.
        protected abstract ResourceType PopulateMetadataForType(Type type, IDictionary knownTypes, IDictionary> childTypes, IEnumerable entitySets);
 
        #endregion Protected methods.
 
        #region Private Methods 

        /// Filter callback for finding IQueryable implementations. 
        /// Type to inspect.
        /// Filter criteria.
        /// true if the specified type is an IQueryable of T; false otherwise.
        private static bool IQueryableTypeFilter(Type m, object filterCriteria) 
        {
            Debug.Assert(m != null, "m != null"); 
            return m.IsGenericType && m.GetGenericTypeDefinition() == typeof(IQueryable<>); 
        }
 
        /// Filter callback for finding IEnumerable implementations.
        /// Type to inspect.
        /// Filter criteria.
        /// true if the specified type is an IEnumerable of T; false otherwise. 
        private static bool IEnumerableTypeFilter(Type m, object filterCriteria)
        { 
            Debug.Assert(m != null, "m != null"); 
            return m.IsGenericType && m.GetGenericTypeDefinition() == typeof(IEnumerable<>);
        } 

        /// Updates the EDM schema version if it is currently lower than .
        /// New version for EDM schema.
        private void UpdateEdmSchemaVersion(MetadataEdmSchemaVersion newVersion) 
        {
            if (this.metadata.EdmSchemaVersion < newVersion) 
            { 
                this.metadata.EdmSchemaVersion = newVersion;
            } 
        }

        /// 
        /// Adds a new  based on the specified  
        /// instance.
        ///  
        /// Method to expose as a service operation. 
        /// Protocol (for example HTTP) method the service operation responds to.
        private void AddServiceOperation(MethodInfo method, string protocolMethod) 
        {
            Debug.Assert(method != null, "method != null");
            Debug.Assert(!method.IsAbstract, "!method.IsAbstract - if method is abstract, the type is abstract - already checked");
 
            // This method is only called for V1 providers, since in case of custom providers,
            // they are suppose to load the metadata themselves. 
            if (this.metadata.ServiceOperations.ContainsKey(method.Name)) 
            {
                throw new InvalidOperationException(Strings.BaseServiceProvider_OverloadingNotSupported(this.Type, method)); 
            }

            bool hasSingleResult = SingleResultAttribute.MethodHasSingleResult(method);
            ServiceOperationResultKind resultKind; 
            ResourceType resourceType = null;
            if (method.ReturnType == typeof(void)) 
            { 
                resultKind = ServiceOperationResultKind.Void;
                this.UpdateEdmSchemaVersion(MetadataEdmSchemaVersion.Version1Dot1); 
            }
            else
            {
                // Load the metadata of the resource type on the fly. 
                // For Edm provider, it might not mean anything, but for reflection service provider, we need to
                // load the metadata of the type if its used only in service operation case 
                Type resultType = null; 
                if (WebUtil.IsPrimitiveType(method.ReturnType))
                { 
                    resultKind = ServiceOperationResultKind.DirectValue;
                    resultType = method.ReturnType;
                    resourceType = ResourceType.GetPrimitiveResourceType(resultType);
                } 
                else
                { 
                    Type queryableElement = GetGenericInterfaceElementType(method.ReturnType, IQueryableTypeFilter); 
                    if (queryableElement != null)
                    { 
                        resultKind = hasSingleResult ?
                            ServiceOperationResultKind.QueryWithSingleResult :
                            ServiceOperationResultKind.QueryWithMultipleResults;
                        resultType = queryableElement; 
                    }
                    else 
                    { 
                        Type enumerableElement = GetIEnumerableElement(method.ReturnType);
                        if (enumerableElement != null) 
                        {
                            resultKind = ServiceOperationResultKind.Enumeration;
                            resultType = enumerableElement;
                        } 
                        else
                        { 
                            resultType = method.ReturnType; 
                            resultKind = ServiceOperationResultKind.DirectValue;
                            this.UpdateEdmSchemaVersion(MetadataEdmSchemaVersion.Version1Dot1); 
                        }
                    }

                    Debug.Assert(resultType != null, "resultType != null"); 
                    resourceType = ResourceType.GetPrimitiveResourceType(resultType);
                    if (resourceType == null) 
                    { 
                        resourceType = this.PopulateMetadataForType(resultType, this.TypeCache, this.ChildTypesCache, this.EntitySets.Values);
                    } 
                }

                if (resourceType == null)
                { 
                    throw new InvalidOperationException(Strings.BaseServiceProvider_UnsupportedReturnType(method, method.ReturnType));
                } 
 
                if (resultKind == ServiceOperationResultKind.Enumeration && hasSingleResult)
                { 
                    throw new InvalidOperationException(Strings.BaseServiceProvider_IEnumerableAlwaysMultiple(this.Type, method));
                }

                if (hasSingleResult || 
                    (!hasSingleResult &&
                    (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType || 
                     resourceType.ResourceTypeKind == ResourceTypeKind.Primitive))) 
                {
                    this.UpdateEdmSchemaVersion(MetadataEdmSchemaVersion.Version1Dot1); 
                }
            }

            ParameterInfo[] parametersInfo = method.GetParameters(); 
            ServiceOperationParameter[] parameters = new ServiceOperationParameter[parametersInfo.Length];
            for (int i = 0; i < parameters.Length; i++) 
            { 
                ParameterInfo parameterInfo = parametersInfo[i];
                if (parameterInfo.IsOut || parameterInfo.IsRetval) 
                {
                    throw new InvalidOperationException(Strings.BaseServiceProvider_ParameterNotIn(method, parameterInfo));
                }
 
                ResourceType parameterType = ResourceType.GetPrimitiveResourceType(parameterInfo.ParameterType);
                if (parameterType == null) 
                { 
                    throw new InvalidOperationException(
                        Strings.BaseServiceProvider_ParameterTypeNotSupported(method, parameterInfo, parameterInfo.ParameterType)); 
                }

                string parameterName = parameterInfo.Name ?? "p" + i.ToString(CultureInfo.InvariantCulture);
                parameters[i] = new ServiceOperationParameter(parameterName, parameterType); 
            }
 
            ResourceSet container = null; 
            if (resourceType != null && resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
            { 
                if (!this.TryFindAnyContainerForType(resourceType, out container))
                {
                    throw new InvalidOperationException(
                        Strings.BaseServiceProvider_ServiceOperationMissingSingleEntitySet(method, resourceType.FullName)); 
                }
            } 
 
            ServiceOperation operation = new ServiceOperation(method.Name, resultKind, resourceType, container, protocolMethod, parameters);
            operation.CustomState = method; 
            MimeTypeAttribute attribute = MimeTypeAttribute.GetMimeTypeAttribute(method);
            if (attribute != null)
            {
                operation.MimeType = attribute.MimeType; 
            }
 
            this.metadata.ServiceOperations.Add(method.Name, operation); 
        }
 
        /// 
        /// Returns the resource type for the corresponding clr type.
        /// If the given clr type is a collection, then resource type describes the element type of the collection.
        ///  
        /// clrType whose corresponding resource type needs to be returned
        /// Returns the resource type 
        private ResourceType GetNonPrimitiveType(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 

            // Check for the type directly first
            ResourceType resourceType;
            if (this.TypeCache.TryGetValue(type, out resourceType)) 
            {
                return resourceType; 
            } 

            // check for ienumerable types 
            Type elementType = BaseServiceProvider.GetIEnumerableElement(type);
            if (elementType != null)
            {
                resourceType = ResourceType.GetPrimitiveResourceType(elementType); 
                if (resourceType == null)
                { 
                    this.TypeCache.TryGetValue(elementType, out resourceType); 
                }
            } 

            return resourceType;
        }
 
        /// 
        /// Looks for the first resource set that the specified  
        /// could belong to. 
        /// 
        /// Type to look for. 
        /// After the method returns, the container to which the type could belong.
        /// true if a container was found; false otherwise.
        private bool TryFindAnyContainerForType(ResourceType type, out ResourceSet container)
        { 
            Debug.Assert(type != null, "type != null");
 
            foreach (ResourceSet c in this.EntitySets.Values) 
            {
                if (c.ResourceType.IsAssignableFrom(type)) 
                {
                    container = c;
                    return true;
                } 
            }
 
            container = default(ResourceSet); 
            return false;
        } 

        #endregion Private Methods

        #region QueryableOverEnumerable 

#if DEBUG 
        /// Implementation of the  interface which only support 
        /// the enumerable portion of the interface.
        /// Used for the old  which returns  
        /// but we require  instead.
        internal class QueryableOverEnumerable : IQueryable
        {
            /// The  this object wraps. 
            private readonly IEnumerable enumerable;
 
            /// Constructor - creates new instance. 
            /// The  to wrap with .
            internal QueryableOverEnumerable(IEnumerable enumerable) 
            {
                this.enumerable = enumerable;
            }
 
            /// The type of the element - not implemented as nothing should call this.
            public Type ElementType 
            { 
                get { throw new NotImplementedException(); }
            } 

            /// The expression for the query - not implemented as nothing should call this.
            public System.Linq.Expressions.Expression Expression
            { 
                get { throw new NotImplementedException(); }
            } 
 
            /// The query provider for this query - not implemented as nothing should call this.
            public IQueryProvider Provider 
            {
                get { throw new NotImplementedException(); }
            }
 
            /// Creates new enumerator of the results of this query.
            /// New  to enumerate results of this query. 
            public IEnumerator GetEnumerator() 
            {
                return this.enumerable.GetEnumerator(); 
            }
        }
#endif
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Abstract Class which contains the common code for ObjectContextServiceProvider
//      and ReflectionServiceProvider 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces.
 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Data.Services.Caching;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq; 
    using System.Reflection;
    using System.ServiceModel.Web; 
 
    #endregion Namespaces.
 
    /// Provides a reflection-based provider implementation.
    internal abstract class BaseServiceProvider : IDataServiceMetadataProvider, IDataServiceQueryProvider, IDisposable, IProjectionProvider, IServiceProvider
    {
        /// Bindings Flags to be used for reflection. 
        protected const BindingFlags ResourceContainerBindingFlags = WebUtil.PublicInstanceBindingFlags;
 
        /// Instance from which data is provided. 
        private object instance;
 
        /// Metadata to be used by the service provider.
        private MetadataCacheItem metadata;

        /// instance of the service to invoke service operations. 
        private object dataServiceInstance;
 
        ///  
        /// Reference back to the provider wrapper.
        ///  
        private DataServiceProviderWrapper providerWrapper;

        /// 
        /// Initializes a new System.Data.Services.BaseServiceProvider instance. 
        /// 
        /// Metadata for this provider. 
        /// data service instance. 
        protected BaseServiceProvider(MetadataCacheItem metadata, object dataServiceInstance)
        { 
            WebUtil.CheckArgumentNull(metadata, "metadata");
            WebUtil.CheckArgumentNull(dataServiceInstance, "dataServiceInstance");
            this.metadata = metadata;
            this.dataServiceInstance = dataServiceInstance; 
        }
 
        #region IDataServiceQueryProvider Properties 

        /// Returns the instance from which data is provided. 
        public object CurrentDataSource
        {
            [DebuggerStepThrough]
            get 
            {
                // Many debuggers will try to display this property, and we don't want to trigger an assertion. 
                Debug.Assert( 
                    System.Diagnostics.Debugger.IsAttached || this.instance != null,
                    "this.instance != null -- otherwise CurrentDataSource is accessed before initialization or after disposal."); 
                return this.instance;
            }

            set 
            {
                WebUtil.CheckArgumentNull(value, "value"); 
                this.instance = value; 
            }
        } 

        /// Gets a value indicating whether null propagation is required in expression trees.
        public abstract bool IsNullPropagationRequired
        { 
            get;
        } 
 
        #endregion IDataServiceQueryProvider Properties
 
        #region IDataServiceMetadataProvider Properties

        /// Namespace name for the EDM container.
        public abstract string ContainerNamespace 
        {
            get; 
        } 

        /// Name of the EDM container 
        public abstract string ContainerName
        {
            get;
        } 

        /// Gets all available containers. 
        /// An enumerable object with all available containers. 
        public IEnumerable ResourceSets
        { 
            get { return this.EntitySets.Values; }
        }

        /// Returns all the types in this data source 
        public IEnumerable Types
        { 
            get { return this.metadata.TypeCache.Values; } 
        }
 
        /// Returns all known service operations.
        public IEnumerable ServiceOperations
        {
            get 
            {
                foreach (ServiceOperation serviceOperation in this.metadata.ServiceOperations.Values) 
                { 
                    yield return serviceOperation;
                } 
            }
        }

        #endregion IDataServiceMetadataProvider Properties 

        /// EDM version to which metadata is compatible. 
        ///  
        /// For example, a service operation of type Void is not acceptable 1.0 CSDL,
        /// so it should use 1.1 CSDL instead. Similarly, OpenTypes are supported 
        /// in 1.2 and not before.
        /// 
        internal MetadataEdmSchemaVersion EdmSchemaVersion
        { 
            get { return this.metadata.EdmSchemaVersion; }
        } 
 
        /// Whether all EPM properties serialize in an Astoria V1-compatible way.
        ///  
        /// This property is false if any property has KeepInContent set to false.
        /// 
        internal bool EpmIsV1Compatible
        { 
            [DebuggerStepThrough]
            get { return this.metadata.EpmIsV1Compatible; } 
        } 

        ///  
        /// Reference back to the provider wrapper.
        /// 
        internal DataServiceProviderWrapper ProviderWrapper
        { 
            set
            { 
                this.providerWrapper = value; 
            }
 
            get
            {
                Debug.Assert(this.providerWrapper != null, "this.providerWrapper != null");
                return this.providerWrapper; 
            }
        } 
 
        /// Returns the list of entity sets.
        protected IDictionary EntitySets 
        {
            [DebuggerStepThrough]
            get { return this.metadata.EntitySets; }
        } 

        /// Target type for the data provider  
        protected Type Type 
        {
            [DebuggerStepThrough] 
            get { return this.metadata.Type; }
        }

        /// Cache of resource properties per type. 
        private Dictionary TypeCache
        { 
            [DebuggerStepThrough] 
            get { return this.metadata.TypeCache; }
        } 

        /// Cache of immediate derived types per type.
        private Dictionary> ChildTypesCache
        { 
            [DebuggerStepThrough]
            get { return this.metadata.ChildTypesCache; } 
        } 

        #region Public Methods 

        /// Applies expansions and projections to the specified .
        ///  object to expand and apply projections to.
        /// The root node of the tree which describes 
        /// the projections and expansions to be applied to the .
        ///  
        /// An  object, with the results including 
        /// the expansions and projections specified in .
        ///  
        /// 
        /// The returned  may implement the  interface
        /// to provide enumerable objects for the expansions; otherwise, the expanded
        /// information is expected to be found directly in the enumerated objects. If paging is 
        /// requested by providing a non-empty list in .OrderingInfo then
        /// it is expected that the topmost  would have a $skiptoken property 
        /// which will be an  in itself and each of it's sub-properties will 
        /// be named SkipTokenPropertyXX where XX represents numbers in increasing order starting from 0. Each of
        /// SkipTokenPropertyXX properties will be used to generated the $skiptoken to support paging. 
        /// If projections are required, the provider may choose to return 
        /// which returns instances of . In that case property values are determined
        /// by calling the  method instead of
        /// accessing properties of the returned object directly. 
        /// If both expansion and projections are required, the provider may choose to return 
        /// of  which in turn returns  from its 
        ///  property. 
        /// 
        public abstract IQueryable ApplyProjections( 
            IQueryable source,
            ProjectionNode projection);

        ///  
        /// 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 abstract ResourceAssociationSet GetResourceAssociationSet(ResourceSet resourceSet, ResourceType resourceType, ResourceProperty resourceProperty);

        ///  
        /// Checks whether the specified  is ordered.
        ///  
        /// Type to check. 
        /// true if the type may be ordered; false otherwise.
        ///  
        /// The ordering may still fail at runtime; this method is currently
        /// used for cleaner error messages only.
        /// 
        public virtual bool GetTypeIsOrdered(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 
            return type == typeof(object) || WebUtil.IsPrimitiveType(type); 
        }
 
        /// 
        /// Returns the requested service
        /// 
        /// type of service you are requesting for. 
        /// returns the instance of the requested service.
        public virtual object GetService(Type serviceType) 
        { 
            if (typeof(IDataServiceMetadataProvider) == serviceType ||
                typeof(IDataServiceQueryProvider) == serviceType || 
                typeof(IProjectionProvider) == serviceType)
            {
                return this;
            } 

            return null; 
        } 

        /// Releases the current data source object as necessary. 
        void IDisposable.Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this); 
        }
 
        #endregion Public Methods 

        #region IDataServiceQueryProvider Methods 

        /// 
        /// 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(ResourceSet container)
        {
            Debug.Assert(container != null, "resourceContainer != null");
            return this.GetResourceContainerInstance(container); 
        }
 
        /// Gets the  for the specified . 
        /// Instance to extract a  from.
        /// The  that describes this  in this provider. 
        public ResourceType GetResourceType(object resource)
        {
            Debug.Assert(resource != null, "instance != null");
            return this.GetNonPrimitiveType(resource.GetType()); 
        }
 
        ///  
        /// Get the value of the strongly typed property.
        ///  
        /// instance of the type declaring the property.
        /// resource property describing the property.
        /// value for the property.
        public object GetPropertyValue(object target, ResourceProperty resourceProperty) 
        {
            Debug.Assert(target != null, "target != null"); 
            Debug.Assert(resourceProperty != null, "resourceProperty != null"); 

            try 
            {
                PropertyInfo propertyInfo = this.GetResourceType(target).GetPropertyInfo(resourceProperty);
                Debug.Assert(propertyInfo != null, "propertyInfo != null");
                return propertyInfo.GetGetMethod().Invoke(target, null); 
            }
            catch (TargetInvocationException exception) 
            { 
                ErrorHandler.HandleTargetInvocationException(exception);
                throw; 
            }
        }

        ///  
        /// Gets the value of the open property.
        ///  
        /// instance of the resource type. 
        /// name of the property.
        /// the value of the open property. If the property is not present, return null. 
        public abstract object GetOpenPropertyValue(object target, string 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. 
        public abstract IEnumerable> GetOpenPropertyValues(object target);
 
        /// 
        /// Invoke the given service operation instance.
        /// 
        /// metadata for the service operation to invoke. 
        /// list of parameters to pass to the service operation.
        /// returns the result by the service operation instance. 
        public object InvokeServiceOperation(ServiceOperation serviceOperation, object[] parameters) 
        {
            return ((MethodInfo)serviceOperation.CustomState).Invoke( 
                    this.dataServiceInstance,
                    BindingFlags.Instance | BindingFlags.Instance | BindingFlags.FlattenHierarchy,
                    null,
                    parameters, 
                    Globalization.CultureInfo.InvariantCulture);
        } 
 
        #endregion IDataServiceQueryProvider Methods
 
        #region IDataServiceMetadataProvider Methods

        /// 
        /// 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"); 
            Debug.Assert(this.ChildTypesCache.ContainsKey(resourceType), "this.ChildTypesCache.ContainsKey(resourceType)"); 

            List childTypes = this.ChildTypesCache[resourceType]; 
            if (childTypes != null)
            {
                foreach (ResourceType childType in childTypes)
                { 
                    yield return childType;
 
                    foreach (ResourceType descendantType in this.GetDerivedTypes(childType)) 
                    {
                        yield return descendantType; 
                    }
                }
            }
        } 

        ///  
        /// 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(resourceType != null, "resourceType != null"); 
            Debug.Assert(this.ChildTypesCache.ContainsKey(resourceType), "this.ChildTypesCache.ContainsKey(resourceType)");
            Debug.Assert(this.ChildTypesCache[resourceType] == null || this.ChildTypesCache[resourceType].Count > 0, "this.ChildTypesCache[resourceType] == null || this.ChildTypesCache[resourceType].Count > 0"); 
 
            return this.ChildTypesCache[resourceType] != null;
        } 

        /// Given the specified name, tries to find a resource set.
        /// Name of the resource set to resolve.
        /// Returns the resolved resource set, null if no resource set for the given name was found. 
        /// True if resource set with the given name was found, false otherwise.
        public bool TryResolveResourceSet(string name, out ResourceSet resourceSet) 
        { 
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");
            return this.EntitySets.TryGetValue(name, out resourceSet); 
        }

        /// Given the specified name, tries to find a service operation.
        /// Name of the service operation to resolve. 
        /// Returns the resolved service operation, null if no service operation was found for the given name.
        /// True if we found the service operation for the given name, false otherwise. 
        public bool TryResolveServiceOperation(string name, out ServiceOperation serviceOperation) 
        {
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)"); 
            return this.metadata.ServiceOperations.TryGetValue(name, out serviceOperation);
        }

        /// Given the specified name, tries to find a type. 
        /// Name of the type to resolve.
        /// Returns the resolved resource type, null if no resource type for the given name was found. 
        /// True if we found the resource type for the given name, false otherwise. 
        public bool TryResolveResourceType(string name, out ResourceType resourceType)
        { 
            Debug.Assert(!string.IsNullOrEmpty(name), "!string.IsNullOrEmpty(name)");
            Debug.Assert(this.metadata != null, "this.metadata != null");
            Debug.Assert(this.TypeCache != null, "this.TypeCache != null");
            foreach (ResourceType t in this.TypeCache.Values) 
            {
                if (t.FullName == name) 
                { 
                    resourceType = t;
                    return true; 
                }
            }

            resourceType = null; 
            return false;
        } 
 
        #endregion IDataServiceMetadataProvider Methods
 
        #region Internal Methods

        /// 
        /// Returns the type of the IEnumerable if the type implements IEnumerable interface; null otherwise. 
        /// 
        /// type that needs to be checked 
        /// Element type if the type implements IEnumerable, else returns null 
        internal static Type GetIEnumerableElement(Type type)
        { 
            return GetGenericInterfaceElementType(type, IEnumerableTypeFilter);
        }

        ///  
        /// Returns the "T" in the IQueryable of T implementation of type.
        ///  
        /// Type to check. 
        /// filter against which the type is checked
        ///  
        /// The element type for the generic IQueryable interface of the type,
        /// or null if it has none or if it's ambiguous.
        /// 
        internal static Type GetGenericInterfaceElementType(Type type, TypeFilter typeFilter) 
        {
            Debug.Assert(type != null, "type != null"); 
            Debug.Assert(!type.IsGenericTypeDefinition, "!type.IsGenericTypeDefinition"); 

            if (typeFilter(type, null)) 
            {
                return type.GetGenericArguments()[0];
            }
 
            Type[] queriables = type.FindInterfaces(typeFilter, null);
            if (queriables != null && queriables.Length == 1) 
            { 
                return queriables[0].GetGenericArguments()[0];
            } 
            else
            {
                return null;
            } 
        }
 
        ///  
        /// Checks whether the provider implements IUpdatable.
        ///  
        /// returns true if the provider implements IUpdatable. otherwise returns false.
        internal abstract bool ImplementsIUpdatable();

        /// Adds service operations based on methods of the specified type. 
        /// Type with methods to add.
        internal void AddOperationsFromType(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
            foreach (MethodInfo methodInfo in type.GetMethods(WebUtil.PublicInstanceBindingFlags | BindingFlags.FlattenHierarchy)) 
            {
                if (methodInfo.GetCustomAttributes(typeof(WebGetAttribute), true).Length != 0)
                {
                    this.AddServiceOperation(methodInfo, XmlConstants.HttpMethodGet); 
                }
                else if (methodInfo.GetCustomAttributes(typeof(WebInvokeAttribute), true).Length != 0) 
                { 
                    this.AddServiceOperation(methodInfo, XmlConstants.HttpMethodPost);
                } 
            }
        }

        /// Populates the metadata for the given provider. 
        internal void PopulateMetadata()
        { 
            Debug.Assert(this.metadata != null, "this.metadata != null -- otherwise we don't have an item to populate"); 
            this.PopulateMetadata(this.TypeCache, this.ChildTypesCache, this.EntitySets);
        } 

        /// 
        /// Applies access rights to entity sets
        ///  
        /// Data service configuration instance with access right info.
        internal void ApplyConfiguration(DataServiceConfiguration configuration) 
        { 
            Debug.Assert(configuration != null, "configuration != null");
 
            this.PopulateMetadataForUserSpecifiedTypes(configuration.GetKnownTypes(), this.TypeCache, this.ChildTypesCache, this.EntitySets.Values);
            this.CheckConfigurationConsistency(this.instance, configuration);
        }
 
        /// Make all the metadata readonly
        internal void MakeMetadataReadonly() 
        { 
            foreach (ResourceSet container in this.ResourceSets)
            { 
                container.SetReadOnly();
            }

            foreach (ResourceType resourceType in this.Types) 
            {
                resourceType.SetReadOnly(); 
                if (!resourceType.EpmIsV1Compatible) 
                {
                    this.metadata.EpmIsV1Compatible = false; 
                }
            }

            foreach (ServiceOperation operation in this.ServiceOperations) 
            {
                operation.SetReadOnly(); 
            } 
        }
 
        #endregion Internal Methods

        #region Protected methods.
 
        /// 
        /// Returns the type of the IQueryable if the type implements IQueryable interface 
        ///  
        /// clr type on which IQueryable check needs to be performed.
        /// Element type if the property type implements IQueryable, else returns null 
        protected static Type GetIQueryableElement(Type type)
        {
            return GetGenericInterfaceElementType(type, IQueryableTypeFilter);
        } 

        ///  
        /// Find the corresponding ResourceType for a given Type, primitive or not 
        /// 
        /// Non-primitive types to search 
        /// Type to look for
        /// Corresponding ResourceType, if found
        /// True if type found, false otherwise
        protected static bool TryGetType(IDictionary knownTypes, Type type, out ResourceType resourceType) 
        {
            Debug.Assert(knownTypes != null, "knownTypes != null"); 
            Debug.Assert(type != null, "type != null"); 

            resourceType = ResourceType.GetPrimitiveResourceType(type); 

            if (resourceType == null)
            {
                knownTypes.TryGetValue(type, out resourceType); 
            }
 
            return resourceType != null; 
        }
 
        /// Checks that the applied configuration is consistent.
        /// Instance of the data source for the provider.
        /// Data service configuration instance with access right info.
        /// At this point in initialization, metadata trimming hasn't taken place. 
        protected virtual void CheckConfigurationConsistency(object dataSourceInstance, DataServiceConfiguration configuration)
        { 
        } 

        /// Releases the current data source object as necessary. 
        /// 
        /// Whether this method is called from an explicit call to Dispose by
        /// the consumer, rather than during finalization.
        ///  
        protected virtual void Dispose(bool disposing)
        { 
            WebUtil.Dispose(this.instance); 
            this.instance = null;
        } 

        /// 
        /// Returns the resource type of the given instance and validates that the instance returns a single resource.
        ///  
        /// clr instance of a resource.
        /// resource type of the given instance. 
        protected ResourceType GetSingleResource(object resource) 
        {
            ResourceType resourceType = this.ProviderWrapper.GetResourceType(resource); 
            return resourceType;
        }

        ///  
        /// Creates the object query for the given resource set and returns it
        ///  
        /// resource set for which IQueryable instance needs to be created 
        /// returns the IQueryable instance for the given resource set
        protected abstract IQueryable GetResourceContainerInstance(ResourceSet resourceContainer); 

        /// 
        /// Populates the metadata for the given provider
        ///  
        /// list of known types
        /// list of known types and their immediate children 
        /// list of entity sets 
        protected abstract void PopulateMetadata(
            IDictionary knownTypes, 
            IDictionary> childTypes,
            IDictionary entitySets);

        ///  
        /// Populate types for metadata specified by the provider
        ///  
        /// list of types specified by the provider 
        /// list of already known types
        /// list of already known types and their immediate children 
        /// list of entity sets as specified in the data source type
        protected abstract void PopulateMetadataForUserSpecifiedTypes(IEnumerable userSpecifiedTypes, IDictionary knownTypes, IDictionary> childTypes, IEnumerable entitySets);

        ///  
        /// Populate metadata for the given clr type.
        ///  
        /// type whose metadata needs to be loaded. 
        /// list of already known resource types.
        /// list of already known types and their immediate children 
        /// list of entity sets as specified in the data source.
        /// resource type containing metadata for the given clr type.
        protected abstract ResourceType PopulateMetadataForType(Type type, IDictionary knownTypes, IDictionary> childTypes, IEnumerable entitySets);
 
        #endregion Protected methods.
 
        #region Private Methods 

        /// Filter callback for finding IQueryable implementations. 
        /// Type to inspect.
        /// Filter criteria.
        /// true if the specified type is an IQueryable of T; false otherwise.
        private static bool IQueryableTypeFilter(Type m, object filterCriteria) 
        {
            Debug.Assert(m != null, "m != null"); 
            return m.IsGenericType && m.GetGenericTypeDefinition() == typeof(IQueryable<>); 
        }
 
        /// Filter callback for finding IEnumerable implementations.
        /// Type to inspect.
        /// Filter criteria.
        /// true if the specified type is an IEnumerable of T; false otherwise. 
        private static bool IEnumerableTypeFilter(Type m, object filterCriteria)
        { 
            Debug.Assert(m != null, "m != null"); 
            return m.IsGenericType && m.GetGenericTypeDefinition() == typeof(IEnumerable<>);
        } 

        /// Updates the EDM schema version if it is currently lower than .
        /// New version for EDM schema.
        private void UpdateEdmSchemaVersion(MetadataEdmSchemaVersion newVersion) 
        {
            if (this.metadata.EdmSchemaVersion < newVersion) 
            { 
                this.metadata.EdmSchemaVersion = newVersion;
            } 
        }

        /// 
        /// Adds a new  based on the specified  
        /// instance.
        ///  
        /// Method to expose as a service operation. 
        /// Protocol (for example HTTP) method the service operation responds to.
        private void AddServiceOperation(MethodInfo method, string protocolMethod) 
        {
            Debug.Assert(method != null, "method != null");
            Debug.Assert(!method.IsAbstract, "!method.IsAbstract - if method is abstract, the type is abstract - already checked");
 
            // This method is only called for V1 providers, since in case of custom providers,
            // they are suppose to load the metadata themselves. 
            if (this.metadata.ServiceOperations.ContainsKey(method.Name)) 
            {
                throw new InvalidOperationException(Strings.BaseServiceProvider_OverloadingNotSupported(this.Type, method)); 
            }

            bool hasSingleResult = SingleResultAttribute.MethodHasSingleResult(method);
            ServiceOperationResultKind resultKind; 
            ResourceType resourceType = null;
            if (method.ReturnType == typeof(void)) 
            { 
                resultKind = ServiceOperationResultKind.Void;
                this.UpdateEdmSchemaVersion(MetadataEdmSchemaVersion.Version1Dot1); 
            }
            else
            {
                // Load the metadata of the resource type on the fly. 
                // For Edm provider, it might not mean anything, but for reflection service provider, we need to
                // load the metadata of the type if its used only in service operation case 
                Type resultType = null; 
                if (WebUtil.IsPrimitiveType(method.ReturnType))
                { 
                    resultKind = ServiceOperationResultKind.DirectValue;
                    resultType = method.ReturnType;
                    resourceType = ResourceType.GetPrimitiveResourceType(resultType);
                } 
                else
                { 
                    Type queryableElement = GetGenericInterfaceElementType(method.ReturnType, IQueryableTypeFilter); 
                    if (queryableElement != null)
                    { 
                        resultKind = hasSingleResult ?
                            ServiceOperationResultKind.QueryWithSingleResult :
                            ServiceOperationResultKind.QueryWithMultipleResults;
                        resultType = queryableElement; 
                    }
                    else 
                    { 
                        Type enumerableElement = GetIEnumerableElement(method.ReturnType);
                        if (enumerableElement != null) 
                        {
                            resultKind = ServiceOperationResultKind.Enumeration;
                            resultType = enumerableElement;
                        } 
                        else
                        { 
                            resultType = method.ReturnType; 
                            resultKind = ServiceOperationResultKind.DirectValue;
                            this.UpdateEdmSchemaVersion(MetadataEdmSchemaVersion.Version1Dot1); 
                        }
                    }

                    Debug.Assert(resultType != null, "resultType != null"); 
                    resourceType = ResourceType.GetPrimitiveResourceType(resultType);
                    if (resourceType == null) 
                    { 
                        resourceType = this.PopulateMetadataForType(resultType, this.TypeCache, this.ChildTypesCache, this.EntitySets.Values);
                    } 
                }

                if (resourceType == null)
                { 
                    throw new InvalidOperationException(Strings.BaseServiceProvider_UnsupportedReturnType(method, method.ReturnType));
                } 
 
                if (resultKind == ServiceOperationResultKind.Enumeration && hasSingleResult)
                { 
                    throw new InvalidOperationException(Strings.BaseServiceProvider_IEnumerableAlwaysMultiple(this.Type, method));
                }

                if (hasSingleResult || 
                    (!hasSingleResult &&
                    (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType || 
                     resourceType.ResourceTypeKind == ResourceTypeKind.Primitive))) 
                {
                    this.UpdateEdmSchemaVersion(MetadataEdmSchemaVersion.Version1Dot1); 
                }
            }

            ParameterInfo[] parametersInfo = method.GetParameters(); 
            ServiceOperationParameter[] parameters = new ServiceOperationParameter[parametersInfo.Length];
            for (int i = 0; i < parameters.Length; i++) 
            { 
                ParameterInfo parameterInfo = parametersInfo[i];
                if (parameterInfo.IsOut || parameterInfo.IsRetval) 
                {
                    throw new InvalidOperationException(Strings.BaseServiceProvider_ParameterNotIn(method, parameterInfo));
                }
 
                ResourceType parameterType = ResourceType.GetPrimitiveResourceType(parameterInfo.ParameterType);
                if (parameterType == null) 
                { 
                    throw new InvalidOperationException(
                        Strings.BaseServiceProvider_ParameterTypeNotSupported(method, parameterInfo, parameterInfo.ParameterType)); 
                }

                string parameterName = parameterInfo.Name ?? "p" + i.ToString(CultureInfo.InvariantCulture);
                parameters[i] = new ServiceOperationParameter(parameterName, parameterType); 
            }
 
            ResourceSet container = null; 
            if (resourceType != null && resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
            { 
                if (!this.TryFindAnyContainerForType(resourceType, out container))
                {
                    throw new InvalidOperationException(
                        Strings.BaseServiceProvider_ServiceOperationMissingSingleEntitySet(method, resourceType.FullName)); 
                }
            } 
 
            ServiceOperation operation = new ServiceOperation(method.Name, resultKind, resourceType, container, protocolMethod, parameters);
            operation.CustomState = method; 
            MimeTypeAttribute attribute = MimeTypeAttribute.GetMimeTypeAttribute(method);
            if (attribute != null)
            {
                operation.MimeType = attribute.MimeType; 
            }
 
            this.metadata.ServiceOperations.Add(method.Name, operation); 
        }
 
        /// 
        /// Returns the resource type for the corresponding clr type.
        /// If the given clr type is a collection, then resource type describes the element type of the collection.
        ///  
        /// clrType whose corresponding resource type needs to be returned
        /// Returns the resource type 
        private ResourceType GetNonPrimitiveType(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 

            // Check for the type directly first
            ResourceType resourceType;
            if (this.TypeCache.TryGetValue(type, out resourceType)) 
            {
                return resourceType; 
            } 

            // check for ienumerable types 
            Type elementType = BaseServiceProvider.GetIEnumerableElement(type);
            if (elementType != null)
            {
                resourceType = ResourceType.GetPrimitiveResourceType(elementType); 
                if (resourceType == null)
                { 
                    this.TypeCache.TryGetValue(elementType, out resourceType); 
                }
            } 

            return resourceType;
        }
 
        /// 
        /// Looks for the first resource set that the specified  
        /// could belong to. 
        /// 
        /// Type to look for. 
        /// After the method returns, the container to which the type could belong.
        /// true if a container was found; false otherwise.
        private bool TryFindAnyContainerForType(ResourceType type, out ResourceSet container)
        { 
            Debug.Assert(type != null, "type != null");
 
            foreach (ResourceSet c in this.EntitySets.Values) 
            {
                if (c.ResourceType.IsAssignableFrom(type)) 
                {
                    container = c;
                    return true;
                } 
            }
 
            container = default(ResourceSet); 
            return false;
        } 

        #endregion Private Methods

        #region QueryableOverEnumerable 

#if DEBUG 
        /// Implementation of the  interface which only support 
        /// the enumerable portion of the interface.
        /// Used for the old  which returns  
        /// but we require  instead.
        internal class QueryableOverEnumerable : IQueryable
        {
            /// The  this object wraps. 
            private readonly IEnumerable enumerable;
 
            /// Constructor - creates new instance. 
            /// The  to wrap with .
            internal QueryableOverEnumerable(IEnumerable enumerable) 
            {
                this.enumerable = enumerable;
            }
 
            /// The type of the element - not implemented as nothing should call this.
            public Type ElementType 
            { 
                get { throw new NotImplementedException(); }
            } 

            /// The expression for the query - not implemented as nothing should call this.
            public System.Linq.Expressions.Expression Expression
            { 
                get { throw new NotImplementedException(); }
            } 
 
            /// The query provider for this query - not implemented as nothing should call this.
            public IQueryProvider Provider 
            {
                get { throw new NotImplementedException(); }
            }
 
            /// Creates new enumerator of the results of this query.
            /// New  to enumerate results of this query. 
            public IEnumerator GetEnumerator() 
            {
                return this.enumerable.GetEnumerator(); 
            }
        }
#endif
        #endregion 
    }
} 

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