/// <summary>
            /// Returns a collection of attributes that are defined on the <paramref name="methodInfo"/> as well as any
            /// underlying interface definitions.
            /// </summary>
            /// <param name="methodInfo">The <see cref="MethodInfo"/> to return attributes for.</param>
            /// <returns>A collection of attributes.</returns>
            private static AttributeCollection GetAttributeCollection(MethodInfo methodInfo)
            {
                // Get all of the attributes defined on the MethodInfo
                List <Attribute> attributes = new List <Attribute>(methodInfo.GetCustomAttributes(true).Cast <Attribute>());

                // Filter out AsyncStateMachineAttribute for "async" methods
                attributes.RemoveAll(a => a.GetType().FullName == "System.Runtime.CompilerServices.AsyncStateMachineAttribute");

                // Examine interfaces on the type and try to find matching method implmentations.
                foreach (Type interfaceType in methodInfo.DeclaringType.GetInterfaces())
                {
                    InterfaceMapping interfaceMapping = methodInfo.DeclaringType.GetInterfaceMap(interfaceType);
                    for (int i = 0; i < interfaceMapping.TargetMethods.Length; ++i)
                    {
                        if (interfaceMapping.TargetMethods[i].MethodHandle == methodInfo.MethodHandle)
                        {
                            // Merge method attributes with those found on the interface method definition
                            ReflectionDomainOperationEntry.MergeAttributes(
                                attributes,
                                interfaceMapping.InterfaceMethods[i].GetCustomAttributes(true).Cast <Attribute>());
                            break;
                        }
                    }
                }

                return(new AttributeCollection(attributes.ToArray()));
            }
        /// <summary>
        /// We need to avoid false positive convention based classification of
        /// Custom methods. This method verifies that candidate Custom methods
        /// have the correct signature.
        /// </summary>
        /// <param name="operation">The operation to inspect</param>
        /// <returns>True if the method has a valid signature</returns>
        private bool IsCustomMethod(ReflectionDomainOperationEntry operation)
        {
            DomainOperationParameter[] parameters = operation.Parameters.ToArray();
            if (parameters.Length == 0 || operation.ReturnType != typeof(void))
            {
                return(false);
            }

            bool first = true;

            foreach (DomainOperationParameter parameter in operation.Parameters)
            {
                if (first)
                {
                    // first parameter must be an entity type
                    if (!this.IsEntityType(parameter.ParameterType))
                    {
                        return(false);
                    }
                    first = false;
                }
                else if (!IsPredefinedOrComplexType(parameter.ParameterType))
                {
                    // all other parameters must be supported serializable types
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// This method classifies an operation by setting its its operation type.
        /// </summary>
        /// <remarks>Domain operations are either explicitly marked with attributes, or they follow a naming/signature convention.</remarks>
        /// <param name="operation">The domain operation to inspect.</param>
        /// <returns>True if the operation is attributed or matches convention; false otherwise.</returns>
        private bool ClassifyDomainOperation(ReflectionDomainOperationEntry operation)
        {
            DomainOperation operationType;

            // Check if explicit attributes exist.
            QueryAttribute queryAtt = (QueryAttribute)operation.Attributes[typeof(QueryAttribute)];

            if (queryAtt != null)
            {
                // query method
                operation.Operation = DomainOperation.Query;
                return(true);
            }
            else if (operation.Attributes[typeof(InsertAttribute)] != null)
            {
                operationType = DomainOperation.Insert;
            }
            else if (operation.Attributes[typeof(UpdateAttribute)] != null)
            {
                // disable obsolete warning here
#pragma warning disable 0618
                if (((UpdateAttribute)operation.Attributes[typeof(UpdateAttribute)]).UsingCustomMethod)
#pragma warning restore 0618
                {
                    operationType = DomainOperation.Custom;
                }
                else
                {
                    operationType = DomainOperation.Update;
                }
            }
            else if (operation.Attributes[typeof(EntityActionAttribute)] != null)
            {
                operationType = DomainOperation.Custom;
            }
            else if (operation.Attributes[typeof(DeleteAttribute)] != null)
            {
                operationType = DomainOperation.Delete;
            }
            else if (operation.Attributes[typeof(InvokeAttribute)] != null)
            {
                operationType = DomainOperation.Invoke;
            }
            else
            {
                return(this.TryClassifyImplicitDomainOperation(operation));
            }

            operation.Operation = operationType;

            return(true);
        }
        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);
        }
        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>
        /// Classifies a domain operation based on naming convention.
        /// </summary>
        /// <param name="operation">The domain operation to inspect.</param>
        /// <returns>True if the operation matches a convention; false otherwise.</returns>
        private bool TryClassifyImplicitDomainOperation(ReflectionDomainOperationEntry operation)
        {
            DomainOperation operationType = (DomainOperation)(-1);

            if (operation.ReturnType == typeof(void))
            {
                // Check if this looks like an insert, update or delete method.
                if (insertPrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Insert;
                }
                else if (updatePrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Update;
                }
                else if (deletePrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Delete;
                }
                else if (this.IsCustomMethod(operation))
                {
                    operationType = DomainOperation.Custom;
                }
            }
            else if (this.IsQueryMethod(operation))
            {
                operationType = DomainOperation.Query;
            }

            if ((int)operationType == -1 && IsInvokeOperation(operation))
            {
                operationType = DomainOperation.Invoke;
            }

            if ((int)operationType != -1)
            {
                operation.Operation  = operationType;
                operation.IsInferred = true;
                return(true);
            }

            return(false);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// This method classifies an operation by setting its its operation type.
        /// </summary>
        /// <remarks>Domain operations are either explicitly marked with attributes, or they follow a naming/signature convention.</remarks>
        /// <param name="operation">The domain operation to inspect.</param>
        /// <returns>True if the operation is attributed or matches convention; false otherwise.</returns>
        private bool ClassifyDomainOperation(ReflectionDomainOperationEntry operation)
        {
            DomainOperation operationType;

            // Check if explicit attributes exist.
            QueryAttribute queryAtt = (QueryAttribute)operation.Attributes[typeof(QueryAttribute)];

            if (queryAtt != null)
            {
                // query method
                operation.Operation = DomainOperation.Query;
                return(true);
            }
            else if (operation.Attributes[typeof(InsertAttribute)] != null)
            {
                operationType = DomainOperation.Insert;
            }
            else if (operation.Attributes[typeof(UpdateAttribute)] != null)
            {
                operationType = DomainOperation.Update;
            }
            else if (operation.Attributes[typeof(EntityActionAttribute)] != null)
            {
                operationType = DomainOperation.Custom;
            }
            else if (operation.Attributes[typeof(DeleteAttribute)] != null)
            {
                operationType = DomainOperation.Delete;
            }
            else if (operation.Attributes[typeof(InvokeAttribute)] != null)
            {
                operationType = DomainOperation.Invoke;
            }
            else
            {
                return(this.TryClassifyImplicitDomainOperation(operation));
            }

            operation.Operation = operationType;

            return(true);
        }
        /// <summary>
        /// We need to avoid false positive convention based classification of
        /// Custom methods. This method verifies that candidate Custom methods
        /// have the correct signature.
        /// </summary>
        /// <param name="operation">The operation to inspect</param>
        /// <returns>True if the method has a valid signature</returns>
        private bool IsCustomMethod(ReflectionDomainOperationEntry operation)
        {
            DomainOperationParameter[] parameters = operation.Parameters.ToArray();
            if (parameters.Length == 0 || operation.ReturnType != typeof(void))
            {
                return false;
            }

            bool first = true;
            foreach (DomainOperationParameter parameter in operation.Parameters)
            {
                if (first)
                {
                    // first parameter must be an entity type
                    if (!this.IsEntityType(parameter.ParameterType))
                    {
                        return false;
                    }
                    first = false;
                }
                else if (!IsPredefinedOrComplexType(parameter.ParameterType))
                {
                    // all other parameters must be supported serializable types
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// Classifies a domain operation based on naming convention.
        /// </summary>
        /// <param name="operation">The domain operation to inspect.</param>
        /// <returns>True if the operation matches a convention; false otherwise.</returns>
        private bool TryClassifyImplicitDomainOperation(ReflectionDomainOperationEntry operation)
        {
            DomainOperation operationType = (DomainOperation)(-1);
            if (operation.ReturnType == typeof(void))
            {
                // Check if this looks like an insert, update or delete method.
                if (insertPrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Insert;
                }
                else if (updatePrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Update;
                }
                else if (deletePrefixes.Any(p => operation.Name.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
                {
                    operationType = DomainOperation.Delete;
                }
                else if (this.IsCustomMethod(operation))
                {
                    operationType = DomainOperation.Custom;
                }
            }
            else if (this.IsQueryMethod(operation))
            {
                operationType = DomainOperation.Query;
            }

            if ((int)operationType == -1 && IsInvokeOperation(operation))
            {
                operationType = DomainOperation.Invoke;
            }

            if ((int)operationType != -1)
            {
                operation.Operation = operationType;
                operation.IsInferred = true;
                return true;
            }

            return false;
        }
        /// <summary>
        /// This method classifies an operation by setting its its operation type.
        /// </summary>
        /// <remarks>Domain operations are either explicitly marked with attributes, or they follow a naming/signature convention.</remarks>
        /// <param name="operation">The domain operation to inspect.</param>
        /// <returns>True if the operation is attributed or matches convention; false otherwise.</returns>
        private bool ClassifyDomainOperation(ReflectionDomainOperationEntry operation)
        {
            DomainOperation operationType;

            // Check if explicit attributes exist.
            QueryAttribute queryAtt = (QueryAttribute)operation.Attributes[typeof(QueryAttribute)];
            if (queryAtt != null)
            {
                // query method
                operation.Operation = DomainOperation.Query;
                return true;
            }
            else if (operation.Attributes[typeof(InsertAttribute)] != null)
            {
                operationType = DomainOperation.Insert;
            }
            else if (operation.Attributes[typeof(UpdateAttribute)] != null)
            {
                // disable obsolete warning here
#pragma warning disable 0618
                if (((UpdateAttribute)operation.Attributes[typeof(UpdateAttribute)]).UsingCustomMethod)
#pragma warning restore 0618
                {
                    operationType = DomainOperation.Custom;
                }
                else
                {
                    operationType = DomainOperation.Update;
                }
            }
            else if (operation.Attributes[typeof(EntityActionAttribute)] != null)
            {
                operationType = DomainOperation.Custom;
            }
            else if (operation.Attributes[typeof(DeleteAttribute)] != null)
            {
                operationType = DomainOperation.Delete;
            }
            else if (operation.Attributes[typeof(InvokeAttribute)] != null)
            {
                operationType = DomainOperation.Invoke;
            }
            else
            {
                return this.TryClassifyImplicitDomainOperation(operation);
            }

            operation.Operation = operationType;

            return true;
        }