/// <summary>
        /// This method returns a collection of attributes representing attributes on the <see cref="DomainService"/> <see cref="Type"/>.
        /// </summary>
        /// <param name="domainServiceType">The <see cref="DomainService"/> <see cref="Type"/>.</param>
        /// <returns>An <see cref="AttributeCollection"/> decorated on the <see cref="Type"/> directly as well as attributes surfaced from interface
        /// implementations.</returns>
        private static AttributeCollection GetDomainServiceTypeAttributes(Type domainServiceType)
        {
            // Get attributes from TypeDescriptor
            List <Attribute> attributes = new List <Attribute>(domainServiceType.Attributes().Cast <Attribute>());

            // All evaluate attributes that exist in interface implementations.
            Type[] interfaces = domainServiceType.GetInterfaces();
            foreach (Type interfaceType in interfaces)
            {
                // Merge attributes together
                ReflectionDomainServiceDescriptionProvider.MergeAttributes(
                    attributes,
                    interfaceType.Attributes().Cast <Attribute>());
            }

            return(new AttributeCollection(attributes.ToArray()));
        }
        /// <summary>
        /// Register the associated metadata provider for Types in the signature
        /// of the specified method as required.
        /// </summary>
        /// <param name="methodInfo">The method to register for.</param>
        private static void RegisterAssociatedMetadataProvider(MethodInfo methodInfo)
        {
            Type type = TypeUtility.GetElementType(methodInfo.ReturnType);

            if (type != typeof(void) && type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).Length != 0)
            {
                ReflectionDomainServiceDescriptionProvider.RegisterAssociatedMetadataTypeTypeDescriptor(type);
            }
            foreach (ParameterInfo parameter in methodInfo.GetParameters())
            {
                type = parameter.ParameterType;
                if (type != typeof(void) && type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).Length != 0)
                {
                    ReflectionDomainServiceDescriptionProvider.RegisterAssociatedMetadataTypeTypeDescriptor(type);
                }
            }
        }
        public override DomainServiceDescription GetDescription()
        {
            DomainServiceDescription description = base.GetDescription();

            // get all type-level attributes
            description.Attributes = ReflectionDomainServiceDescriptionProvider.GetDomainServiceTypeAttributes(description.DomainServiceType);

            // get all public candidate methods and create the operations
            List <ReflectionDomainOperationEntry> operationEntries = new List <ReflectionDomainOperationEntry>();
            IEnumerable <MethodInfo> methodsToInspect =
                description.DomainServiceType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                .Where(p => (p.DeclaringType != typeof(DomainService) && (p.DeclaringType != typeof(object))) && !p.IsSpecialName);

            foreach (MethodInfo method in methodsToInspect)
            {
                // We need to ensure the buddy metadata provider is registered before we
                // attempt to do convention, since we rely on IsEntity which relies on
                // KeyAttributes being present
                RegisterAssociatedMetadataProvider(method);

                if (method.GetCustomAttributes(typeof(IgnoreAttribute), false).Length > 0)
                {
                    continue;
                }

                if (method.IsVirtual && method.GetBaseDefinition().DeclaringType == typeof(DomainService))
                {
                    // don't want to infer overrides of DomainService virtual methods as
                    // operations
                    continue;
                }

                ReflectionDomainOperationEntry operation = new ReflectionDomainOperationEntry(description.DomainServiceType, method, (DomainOperation)(-1));
                if (this.ClassifyDomainOperation(operation))
                {
                    operationEntries.Add(operation);
                }
            }

            foreach (DomainOperationEntry operation in operationEntries)
            {
                description.AddOperation(operation);
            }

            return(description);
        }
        /// <summary>
        /// Creates and returns the description provider for the specified domain service Type.
        /// </summary>
        /// <param name="domainServiceType">The domain service Type.</param>
        /// <returns>The description provider.</returns>
        internal static DomainServiceDescriptionProvider CreateDescriptionProvider(Type domainServiceType)
        {
            // construct a list of all types in the inheritance hierarchy for the service
            List<Type> baseTypes = new List<Type>();
            Type currType = domainServiceType;
            while (currType != typeof(DomainService))
            {
                baseTypes.Add(currType);
                currType = currType.BaseType;
            }

            // create our base reflection provider
            List<DomainServiceDescriptionProvider> descriptionProviderList = new List<DomainServiceDescriptionProvider>();
            ReflectionDomainServiceDescriptionProvider reflectionDescriptionProvider = new ReflectionDomainServiceDescriptionProvider(domainServiceType);

            // set the IsEntity function which consults the chain of providers.
            Func<Type, bool> isEntityTypeFunc = (t) => descriptionProviderList.Any(p => p.LookupIsEntityType(t));
            reflectionDescriptionProvider.SetIsEntityTypeFunc(isEntityTypeFunc);

            // Now from most derived to base, create any declared description providers,
            // chaining the instances as we progress. Note that ordering from derived to
            // base is important - we want to ensure that any DSDPs the user has placed on
            // their DomainService directly come before an DAL providers.
            DomainServiceDescriptionProvider currProvider = reflectionDescriptionProvider;
            descriptionProviderList.Add(currProvider);
            for (int i = 0; i < baseTypes.Count; i++)
            {
                currType = baseTypes[i];

                // Reflection rather than TD is used here so we only get explicit
                // Type attributes. TD inherits attributes by default, even if the
                // attributes aren't inheritable.
                foreach (DomainServiceDescriptionProviderAttribute providerAttribute in
                    currType.GetCustomAttributes(typeof(DomainServiceDescriptionProviderAttribute), false))
                {
                    currProvider = providerAttribute.CreateProvider(domainServiceType, currProvider);
                    currProvider.SetIsEntityTypeFunc(isEntityTypeFunc);
                    descriptionProviderList.Add(currProvider);
                }
            }

            return currProvider;
        }