/// <summary>
        /// Get a ReflectedControl for the given markup tag, if one exists, restricting the search
        /// to just class types that are included in the allowed-types list (or types that inherit from them).
        /// </summary>
        /// <param name="compileContext">The context in which errors should be reported.</param>
        /// <param name="tag">The complete markup tag to search for.</param>
        /// <param name="allowedTypes">The allowed types that can be returned.  If you want to accept
        /// all possible types, pass in a list containing just typeof(object).</param>
        /// <returns>The found control type.</returns>
        public ReflectedControl GetControl(ICompileContext compileContext, Tag tag, IEnumerable <Type> allowedTypes)
        {
            bool isNormalServerControl = tag.TagName.Contains(":");

            if (isNormalServerControl && _reflectedControls.ContainsKey(tag.TagName))
            {
                return(_reflectedControls[tag.TagName]);
            }

            ReflectedControl reflectedControl = new ReflectedControl(compileContext, tag, _tagRegistrations, _assemblies, allowedTypes);

            if (isNormalServerControl && tag.TagName.Contains(":"))
            {
                _reflectedControls[tag.TagName] = reflectedControl;
            }

            return(reflectedControl);
        }
        /// <summary>
        /// Construct an instance of a ReflectedControlProperty, given the control for this property and the
        /// pre-reflected PropertyInfo for the property in question.
        /// </summary>
        /// <param name="reflectedControl">The control that owns this property.</param>
        /// <param name="propertyInfo">The pre-reflected PropertyInfo for this property.</param>
        public ReflectedControlProperty(ReflectedControl reflectedControl, PropertyInfo propertyInfo)
        {
            ReflectedControl = reflectedControl;
            PropertyInfo     = propertyInfo;

            System.Web.UI.PersistenceModeAttribute[] persistenceModeAttributes = (System.Web.UI.PersistenceModeAttribute[])propertyInfo.GetCustomAttributes(typeof(System.Web.UI.PersistenceModeAttribute), true);
            PersistenceModeAttribute = persistenceModeAttributes.Length == 0 ? null : persistenceModeAttributes[0];

            IsTemplateProperty   = typeof(System.Web.UI.ITemplate).IsAssignableFrom(PropertyInfo.PropertyType);
            IsCollectionProperty = typeof(IEnumerable).IsAssignableFrom(PropertyInfo.PropertyType) && !IsTemplateProperty;

            if (IsTemplateProperty)
            {
                System.Web.UI.TemplateInstanceAttribute[] templateInstanceAttributes = (System.Web.UI.TemplateInstanceAttribute[])propertyInfo.GetCustomAttributes(typeof(System.Web.UI.TemplateInstanceAttribute), true);
                TemplateInstanceAttribute = templateInstanceAttributes.Length == 0 ? null : templateInstanceAttributes[0];

                System.Web.UI.TemplateContainerAttribute[] templateContainerAttributes = (System.Web.UI.TemplateContainerAttribute[])propertyInfo.GetCustomAttributes(typeof(System.Web.UI.TemplateContainerAttribute), true);
                TemplateContainerAttribute = templateContainerAttributes.Length == 0 ? null : templateContainerAttributes[0];
            }
            else if (IsCollectionProperty)
            {
                CollectionItemTypes = GetCollectionItemTypes(PropertyInfo.PropertyType);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Find all of the properties for this control, via reflection.
        /// </summary>
        /// <returns>A dictionary of properties for the given control type.</returns>
        private static Dictionary <string, ReflectedControlProperty> CollectControlProperties(ICompileContext compileContext, Type controlType, ReflectedControl reflectedControl)
        {
            Dictionary <string, ReflectedControlProperty> controlProperties = new Dictionary <string, ReflectedControlProperty>();

            // We have to include NonPublic properties, since internal, public, or protected properties can all be
            // legally referenced from the markup.
            PropertyInfo[] propertyInfos = controlType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                // Find out what kind of getters and setter this property has.  If it has none, or both of them are private, we can't work with it.
                MethodInfo setMethodInfo      = propertyInfo.GetSetMethod(true);
                MethodInfo getMethodInfo      = propertyInfo.GetGetMethod(true);
                bool       hasUsableSetMethod = (setMethodInfo != null && (setMethodInfo.IsPublic || setMethodInfo.IsFamilyOrAssembly));
                bool       hasUsableGetMethod = (getMethodInfo != null && (getMethodInfo.IsPublic || getMethodInfo.IsFamilyOrAssembly));
                if (!hasUsableSetMethod && !hasUsableGetMethod)
                {
                    continue;
                }

                // We have a public-ish setter.  So add a ReflectedControlProperty instance for this property,
                // since it could be accessible from markup.
                ReflectedControlProperty reflectedControlProperty = new ReflectedControlProperty(reflectedControl, propertyInfo);

                // Add it to the set of known properties for this control.  We don't have the ability to support
                // case differentiation on property names, and ASP.NET will bork if anybody tries.  So if you have
                // multiple properties with the same name that differ only by case, that's just bad mojo, and you
                // should change your controls so that isn't true anymore.
                string lowerName = propertyInfo.Name.ToLower();
                if (controlProperties.ContainsKey(lowerName))
                {
                    ReflectedControlProperty previousProperty  = controlProperties[lowerName];
                    Type         previousPropertyDeclaringType = previousProperty.PropertyInfo.DeclaringType;
                    PropertyInfo baseProperty = previousPropertyDeclaringType.BaseType.GetProperty(lowerName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
                    if (baseProperty == null)
                    {
                        compileContext.Warning(string.Format("The server control \"{0}\" contains multiple properties named \"{1}\".  Keeping the {2} declaration and discarding the {3} declaration.",
                                                             controlType.FullName, propertyInfo.Name, controlProperties[lowerName].PropertyInfo.PropertyType.FullName, propertyInfo.PropertyType.FullName));
                    }
                    else
                    {
                        // This appears to be a case of a child class's property shadowing a parent class's property.
                        // That's a safe thing, or should be, so we don't throw out a warning when it happens.
                        compileContext.Verbose(string.Format("The server control \"{0}\" contains multiple properties named \"{1}\" (but one comes from a parent class, so the 'new' keyword was probably involved, and this should be safe).  Keeping the {2} declaration and discarding the {3} declaration.",
                                                             controlType.FullName, propertyInfo.Name, controlProperties[lowerName].PropertyInfo.PropertyType.FullName, propertyInfo.PropertyType.FullName));
                    }
                    continue;
                }
                controlProperties.Add(lowerName, reflectedControlProperty);
            }

            return(controlProperties);
        }