/// <summary>
        /// Gets vocabulary annotation that binds to a term and a qualifier from the metadata annotation dictionary in current data service context for a specified type.
        /// </summary>
        /// <param name="context">The data service context.</param>
        /// <param name="type">The specified annotated type.</param>
        /// <param name="term">The term name.</param>
        /// <param name="qualifier">The qualifier name.</param>
        /// <returns>The vocabulary annotation that binds to a term and a qualifier for the specified annotated type.</returns>
        private static IEdmVocabularyAnnotation GetOrInsertCachedMetadataAnnotationForType(DataServiceContext context, Type type, string term, string qualifier)
        {
            var serviceModel = context.Format.ServiceModel;

            if (serviceModel == null)
            {
                return(null);
            }

            IEdmVocabularyAnnotation edmValueAnnotation = GetCachedMetadataAnnotation(context, type, term, qualifier);

            if (edmValueAnnotation != null)
            {
                return(edmValueAnnotation);
            }

            IEdmVocabularyAnnotatable edmVocabularyAnnotatable = null;

            if (type.IsSubclassOf(typeof(DataServiceContext)))
            {
                edmVocabularyAnnotatable = serviceModel.EntityContainer;
            }
            else
            {
                var serversideName = context.ResolveName == null ? type.FullName : context.ResolveName(type);
                if (!string.IsNullOrWhiteSpace(serversideName))
                {
                    edmVocabularyAnnotatable = serviceModel.FindDeclaredType(serversideName);
                    if (edmVocabularyAnnotatable == null)
                    {
                        return(null);
                    }
                }
            }

            // Gets the annotations which exactly match the qualifier and target.
            var edmValueAnnotations = serviceModel.FindVocabularyAnnotations <IEdmVocabularyAnnotation>(edmVocabularyAnnotatable, term, qualifier)
                                      .Where(a => a.Qualifier == qualifier && a.Target == edmVocabularyAnnotatable);

            if (!edmValueAnnotations.Any())
            {
                edmValueAnnotation = GetOrInsertCachedMetadataAnnotationForType(context, type.GetBaseType(), term, qualifier);
            }
            else if (edmValueAnnotations.Count() == 1)
            {
                edmValueAnnotation = edmValueAnnotations.Single();
            }

            InsertMetadataAnnotation(context, type, edmValueAnnotation);
            return(edmValueAnnotation);
        }
        /// <summary>
        /// Gets vocabulary annotation that binds to a term and a qualifier from the metadata annotation dictionary in current data service context for a specified propertyInfo.
        /// </summary>
        /// <param name="context">The data service context.</param>
        /// <param name="propertyInfo">The specified annotated propertyInfo.</param>
        /// <param name="term">The term name.</param>
        /// <param name="qualifier">The qualifier name.</param>
        /// <returns>The vocabulary annotation that binds to a term and a qualifier for the specified annotated propertyInfo.</returns>
        private static IEdmVocabularyAnnotation GetOrInsertCachedMetadataAnnotationForPropertyInfo(DataServiceContext context, PropertyInfo propertyInfo, string term, string qualifier)
        {
            var serviceModel = context.Format.ServiceModel;

            if (serviceModel == null)
            {
                return(null);
            }

            IEdmVocabularyAnnotation edmValueAnnotation = GetCachedMetadataAnnotation(context, propertyInfo, term, qualifier);

            if (edmValueAnnotation != null)
            {
                return(edmValueAnnotation);
            }

            var severSidePropertyName = ClientTypeUtil.GetServerDefinedName(propertyInfo);

            if (string.IsNullOrEmpty(severSidePropertyName))
            {
                return(null);
            }

            var declaringType = propertyInfo.DeclaringType;
            IEnumerable <IEdmVocabularyAnnotation> edmValueAnnotations = null;

            if (declaringType.IsSubclassOf(typeof(DataServiceContext)))
            {
                var entityContainer            = serviceModel.EntityContainer;
                var edmEntityContainerElements = entityContainer.Elements.Where(e => e.Name == severSidePropertyName);
                if (edmEntityContainerElements != null && edmEntityContainerElements.Count() == 1)
                {
                    edmValueAnnotations = serviceModel.FindVocabularyAnnotations <IEdmVocabularyAnnotation>(
                        edmEntityContainerElements.Single(), term, qualifier).Where(a => a.Qualifier == qualifier);
                }
            }
            else
            {
                var serversideTypeName = context.ResolveName == null ? declaringType.FullName : context.ResolveName(declaringType);
                var edmType            = serviceModel.FindDeclaredType(serversideTypeName);
                if (edmType != null)
                {
                    var edmStructuredType = edmType as IEdmStructuredType;
                    if (edmStructuredType != null)
                    {
                        var edmProperty = edmStructuredType.FindProperty(severSidePropertyName);
                        if (edmProperty != null)
                        {
                            edmValueAnnotations = serviceModel.FindVocabularyAnnotations <IEdmVocabularyAnnotation>(
                                edmProperty, term, qualifier).Where(a => a.Qualifier == qualifier);
                        }
                    }
                }
            }

            if (edmValueAnnotations != null && edmValueAnnotations.Count() == 1)
            {
                edmValueAnnotation = edmValueAnnotations.Single();
                InsertMetadataAnnotation(context, propertyInfo, edmValueAnnotation);
                return(edmValueAnnotation);
            }

            return(null);
        }
        /// <summary>
        /// Get Edm operation according to the MethodInfo from current data service context.
        /// </summary>
        /// <param name="context">The data service context.</param>
        /// <param name="methodInfo">The specified MethodInfo</param>
        /// <returns>The related <see cref="IEdmOperation"/> will be returned if it is found, or return null.</returns>
        internal static IEdmOperation GetEdmOperation(DataServiceContext context, MethodInfo methodInfo)
        {
            var serviceModel = context.Format.ServiceModel;

            if (serviceModel == null)
            {
                return(null);
            }

            var  parameterTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
            Type bindingType    = null;
            IEnumerable <Type> clientParameters;

            if (methodInfo.IsDefined(typeof(ExtensionAttribute), false))
            {
                bindingType      = parameterTypes.First();
                clientParameters = parameterTypes.Skip(1);
            }
            else
            {
                bindingType      = methodInfo.DeclaringType;
                clientParameters = parameterTypes;
            }

            var declaringType = methodInfo.DeclaringType;

            string methodInfoNameSpacePrefix = declaringType.Namespace + ".";

            if (context.ResolveName != null)
            {
                string serverSideDeclaringTypeName = context.ResolveName(declaringType);
                if (serverSideDeclaringTypeName != null)
                {
                    int index = serverSideDeclaringTypeName.LastIndexOf('.');
                    methodInfoNameSpacePrefix = index > 0 ? serverSideDeclaringTypeName.Substring(0, index + 1) : "";
                }
            }

            var serverSideMethodName = ClientTypeUtil.GetServerDefinedName(methodInfo);
            var operations           = serviceModel.FindOperations(methodInfoNameSpacePrefix + serverSideMethodName).Where(o => o.IsBound);

            while (bindingType != null)
            {
                foreach (var operation in operations)
                {
                    Type bindingTypeFromTypeReference;

                    if (TryGetClrTypeFromEdmTypeReference(
                            context,
                            operation.Parameters.First().Type,
                            methodInfo.IsDefined(typeof(ExtensionAttribute), false),
                            out bindingTypeFromTypeReference) &&
                        bindingTypeFromTypeReference == bindingType &&
                        clientParameters.SequenceEqual(GetNonBindingParameterTypeArray(context, operation.Parameters, true)))
                    {
                        return(operation);
                    }
                }

                if (methodInfo.IsDefined(typeof(ExtensionAttribute), false) && bindingType.IsGenericType())
                {
                    var genericTypeDefinition = bindingType.GetGenericTypeDefinition();
                    var genericArguments      = bindingType.GetGenericArguments().ToList();
                    if (genericArguments.Count == 1)
                    {
                        var genericArgumentBaseType = genericArguments[0].GetBaseType();
                        if (genericArgumentBaseType != null)
                        {
                            bindingType = genericTypeDefinition.MakeGenericType(genericArgumentBaseType);
                            continue;
                        }
                    }
                }

                return(null);
            }

            return(null);
        }