private void ReplaceTypRefAttributeWithTypeAndAssembly([NotNull] XmlElement xmlElement,
                                                               ConfigurationFileMutationType configurationFileMutationType)
        {
            if (configurationFileMutationType == ConfigurationFileMutationType.None)
            {
                return;
            }

            string typeRefAttributeName  = null;
            string typeAttributeName     = null;
            var    assemblyAttributeName = ConfigurationFileAttributeNames.Assembly;

            if (xmlElement.HasAttribute(ConfigurationFileAttributeNames.TypeRef))
            {
                typeRefAttributeName = ConfigurationFileAttributeNames.TypeRef;
                typeAttributeName    = ConfigurationFileAttributeNames.Type;
            }
            else if (xmlElement.HasAttribute(ConfigurationFileAttributeNames.InterfaceRef))
            {
                typeRefAttributeName = ConfigurationFileAttributeNames.InterfaceRef;
                typeAttributeName    = ConfigurationFileAttributeNames.Interface;
            }
            else if (xmlElement.HasAttribute(ConfigurationFileAttributeNames.SerializerAggregatorTypeRef))
            {
                typeRefAttributeName = ConfigurationFileAttributeNames.SerializerAggregatorTypeRef;
                typeAttributeName    = ConfigurationFileAttributeNames.SerializerAggregatorType;
            }

            if (typeRefAttributeName == null)
            {
                return;
            }

            var elementPath = GetElementPath(xmlElement);

            LogHelper.Context.Log.Info($"Started mutating element '{elementPath}'.");

            INamedTypeDefinitionElement namedTypeDefinitionElement = null;
            var typeRefAttributeValue = xmlElement.GetAttribute(typeRefAttributeName);

            xmlElement.RemoveAttribute(typeRefAttributeName);

            {
                var currentXmlElement = xmlElement;
                while (currentXmlElement != null && !currentXmlElement.Name.Equals("iocConfiguration", StringComparison.Ordinal))
                {
                    if (currentXmlElement.Name.Equals(ConfigurationFileElementNames.PluginSetup))
                    {
                        if (currentXmlElement.GetAttribute(ConfigurationFileAttributeNames.Plugin).Equals(Plugin1Name))
                        {
                            namedTypeDefinitionElement = _pluginTypeDefinitionsElement.GetTypeDefinition(typeRefAttributeValue);
                            break;
                        }

                        Assert.Fail("Test only Plugin1");
                    }
                    currentXmlElement = currentXmlElement.ParentNode as XmlElement;
                }
            }

            if (namedTypeDefinitionElement == null)
            {
                namedTypeDefinitionElement = _typeDefinitionsElement.GetTypeDefinition(typeRefAttributeValue);
            }

            Assert.IsNotNull(namedTypeDefinitionElement);

            var typeFullNameInConfigFile = GetConfigStyleTypeName(namedTypeDefinitionElement);

            xmlElement.SetAttributeValue(typeAttributeName, typeFullNameInConfigFile);


            LogHelper.Context.Log.Info($"Mutated element '{elementPath}': The value of attribute {typeRefAttributeName}='{typeRefAttributeValue}' was replaced with attribute {typeAttributeName}='{typeFullNameInConfigFile}'");

            if (configurationFileMutationType == ConfigurationFileMutationType.UseTypeAndAssembly)
            {
                xmlElement.SetAttributeValue(assemblyAttributeName, namedTypeDefinitionElement.ValueTypeInfo.Assembly.Alias);

                LogHelper.Context.Log.Info($"Mutated element '{elementPath}': Added attribute {assemblyAttributeName}='{namedTypeDefinitionElement.ValueTypeInfo.Assembly.Alias}'");
            }
        }
Пример #2
0
        public ClassMemberData GetClassMemberData(IConfigurationFileElement configurationFileElement, string classMemberPath,
                                                  IEnumerable <IParameter> parameters)
        {
            ITypeInfo classInfo = null;
            ITypeInfo memberTypeInfo;
            string    classMemberName = null;

            Type[] parameterTypes = parameters.Select(x => x.ValueTypeInfo.Type).ToArray();

            var allMatchedMemberInfos = new List <MemberInfo>();
            var isStaticMember        = true;
            var classMemberCategory   = ClassMemberCategory.Field;

            var lastIndexofDot = classMemberPath.LastIndexOf('.');

            if (lastIndexofDot > 0 && lastIndexofDot + 1 < classMemberPath.Length)
            {
                classMemberName = classMemberPath.Substring(lastIndexofDot + 1).Trim();
            }

            if (string.IsNullOrEmpty(classMemberName))
            {
                throw new ConfigurationParseException(configurationFileElement, $"No class member is specified in '{classMemberPath}'. {ExamplesOfValidClassPaths}");
            }

            var typeFullName = classMemberPath.Substring(0, lastIndexofDot).Trim();

            if (typeFullName.Length == 0)
            {
                throw new ConfigurationParseException(configurationFileElement, $"No class name is provided in {classMemberPath}. {ExamplesOfValidClassPaths}");
            }

            INamedTypeDefinitionElement namedTypeDefinitionElement = null;

            if (!typeFullName.Contains("."))
            {
                namedTypeDefinitionElement = configurationFileElement.GetTypeDefinition(typeFullName);

                if (namedTypeDefinitionElement != null)
                {
                    classInfo = namedTypeDefinitionElement.ValueTypeInfo;
                    _pluginAssemblyTypeUsageValidator.Validate(configurationFileElement, classInfo);
                }
            }

            if (classInfo == null)
            {
                classInfo = _typeHelper.GetTypeInfoFromTypeFullName(configurationFileElement, typeFullName);
            }

            if (classInfo.Type.IsEnum)
            {
                if (classInfo.Type.GetEnumNames().FirstOrDefault(x => classMemberName.Equals(x, StringComparison.Ordinal)) == null)
                {
                    throw new ConfigurationParseException(configurationFileElement, $"Enumeration value '{classMemberName}' is not defined in enumeration '{classInfo.TypeCSharpFullName}'.");
                }

                allMatchedMemberInfos.Add(classInfo.Type.GetMember(classMemberName).First());
                classMemberCategory = ClassMemberCategory.EnumValue;
                isStaticMember      = true;
                memberTypeInfo      = classInfo;
            }
            else
            {
                Type memberReturnType = null;

                void processType(Type type, ref bool stopProcessingParam)
                {
                    MemberInfo memberInfo = null;

                    try
                    {
                        if (parameterTypes.Length > 0)
                        {
                            // Lets try to find a method first.
                            var methodInfo = type.GetMethods().FirstOrDefault(x =>
                                                                              Helpers.IsMethodAMatch(x, classMemberName, parameterTypes));

                            if (methodInfo != null)
                            {
                                memberInfo = methodInfo;

                                classMemberCategory = ClassMemberCategory.Method;
                                isStaticMember      = methodInfo.IsStatic;
                                memberReturnType    = methodInfo.ReturnType;
                            }

                            return;
                        }

                        var memberInfos = type.GetMembers().Where(x =>
                                                                  classMemberName.Equals(x.Name, StringComparison.Ordinal)).ToList();

                        if (memberInfos.Count == 0)
                        {
                            return;
                        }


                        if (memberInfos[0] is MethodInfo)
                        {
                            var methodInfo = (MethodInfo)memberInfos.FirstOrDefault(x => x is MethodInfo methodInfo2 &&
                                                                                    methodInfo2.IsPublic &&
                                                                                    methodInfo2.GetParameters().Length == 0);
                            if (methodInfo == null)
                            {
                                return;
                            }

                            memberInfo          = methodInfo;
                            classMemberCategory = ClassMemberCategory.Method;
                            isStaticMember      = methodInfo.IsStatic;
                            memberReturnType    = methodInfo.ReturnType;
                        }
                        else
                        {
                            memberInfo = memberInfos[0];

                            if (memberInfo is FieldInfo fieldInfo)
                            {
                                if (!fieldInfo.IsPublic)
                                {
                                    return;
                                }

                                classMemberCategory = ClassMemberCategory.Field;
                                isStaticMember      = fieldInfo.IsStatic || fieldInfo.IsLiteral;
                                memberReturnType    = fieldInfo.FieldType;
                            }
                            else if (memberInfo is PropertyInfo propertyInfo)
                            {
                                var getMethod = propertyInfo.GetGetMethod();

                                if (!getMethod.IsPublic)
                                {
                                    return;
                                }

                                classMemberCategory = ClassMemberCategory.Property;
                                isStaticMember      = getMethod.IsStatic;
                                memberReturnType    = getMethod.ReturnType;
                            }
                        }
                    }
                    finally
                    {
                        if (memberInfo != null)
                        {
                            allMatchedMemberInfos.Add(memberInfo);

                            if (type == classInfo.Type)
                            {
                                stopProcessingParam = true;
                            }
                        }
                    }
                }

                var stopProcessing = false;
                _typeMemberLookupHelper.ProcessTypeImplementedInterfacesAndBaseTypes(classInfo.Type, processType, ref stopProcessing);

                if (allMatchedMemberInfos.Count == 1)
                {
                    memberTypeInfo = _typeHelper.GetTypeInfoFromType(configurationFileElement, memberReturnType);
                }
                else
                {
                    var errorMessage = new StringBuilder();
                    errorMessage.AppendFormat("Member with name '{0}'", classMemberName);

                    if (parameterTypes.Length > 0)
                    {
                        errorMessage.AppendFormat(" and parameters of types: ({0})",
                                                  string.Join(",", parameters.Select(x => x.ValueTypeInfo.TypeCSharpFullName)));
                    }
                    else
                    {
                        errorMessage.Append(" and zero parameters");
                    }


                    if (allMatchedMemberInfos.Count == 0)
                    {
                        errorMessage.AppendFormat(" was not found in type '{0}' or any of its parents.", classInfo.TypeCSharpFullName);
                        errorMessage.AppendLine();
                    }
                    else
                    {
                        errorMessage.AppendFormat(" was not found in type '{0}', however a member with this name occurs multiple times in parents of type '{0}'.",
                                                  classInfo.TypeCSharpFullName);
                        errorMessage.AppendLine();

                        errorMessage.AppendLine("Please specify one of the parent types where the member is declared.");

                        errorMessage.AppendFormat($"Note, if necessary, you can use '{0}' to proxy the service '{1}'.",
                                                  ConfigurationFileElementNames.ProxyService, classInfo.TypeCSharpFullName);
                        errorMessage.AppendLine();

                        errorMessage.AppendLine(MessagesHelper.GenerateProxyServiceExample(allMatchedMemberInfos[0].DeclaringType, classInfo.Type));

                        errorMessage.AppendLine(
                            string.Format("The following is the list of types, where the member named '{0}' was found: {1}",
                                          classMemberName,
                                          string.Join(", ", allMatchedMemberInfos.Select(x => x.DeclaringType.GetTypeNameInCSharpClass()))));
                    }

                    throw new ConfigurationParseException(configurationFileElement, errorMessage.ToString());
                }
            }

            return(new ClassMemberData(classInfo, memberTypeInfo, allMatchedMemberInfos[0], parameters, !isStaticMember, classMemberCategory));
        }