/// <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); }
/// <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; }