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