The Labs \ Source Viewer \ SSCLI \ System.Configuration \ ConfigurationProperty

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ConfigurationProperty.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.ComponentModel;
  17. using System.Security.Permissions;
  18. using System.Collections.Generic;
  19. using System.Collections.Specialized;
  20. using System.Reflection;
  21. using System.Text;
  22. namespace System.Configuration
  23. {
  24.    
  25.     public sealed class ConfigurationProperty
  26.     {
  27.         static internal readonly ConfigurationValidatorBase NonEmptyStringValidator = new StringValidator(1);
  28.         private static readonly ConfigurationValidatorBase DefaultValidatorInstance = new DefaultValidator();
  29.         static internal readonly string DefaultCollectionPropertyName = "";
  30.         private string _name;
  31.         private string _providedName;
  32.         private string _description;
  33.         private Type _type;
  34.         private object _defaultValue;
  35.         private TypeConverter _converter;
  36.         private ConfigurationPropertyOptions _options;
  37.         private ConfigurationValidatorBase _validator;
  38.         private string _addElementName = null;
  39.         private string _removeElementName = null;
  40.         private string _clearElementName = null;
  41.        
  42.         public ConfigurationProperty(string name, Type type)
  43.         {
  44.             object defaultValue = null;
  45.            
  46.             ConstructorInit(name, type, ConfigurationPropertyOptions.None, null, null);
  47.            
  48.             if (type == typeof(string)) {
  49.                 defaultValue = String.Empty;
  50.             }
  51.             else if (type.IsValueType) {
  52.                 defaultValue = TypeUtil.CreateInstanceWithReflectionPermission(type);
  53.             }
  54.             SetDefaultValue(defaultValue);
  55.         }
  56.        
  57.         public ConfigurationProperty(string name, Type type, object defaultValue) : this(name, type, defaultValue, ConfigurationPropertyOptions.None)
  58.         {
  59.         }
  60.        
  61.         public ConfigurationProperty(string name, Type type, object defaultValue, ConfigurationPropertyOptions options) : this(name, type, defaultValue, null, null, options)
  62.         {
  63.         }
  64.        
  65.         public ConfigurationProperty(string name, Type type, object defaultValue, TypeConverter typeConverter, ConfigurationValidatorBase validator, ConfigurationPropertyOptions options) : this(name, type, defaultValue, typeConverter, validator, options, null)
  66.         {
  67.         }
  68.        
  69.         public ConfigurationProperty(string name, Type type, object defaultValue, TypeConverter typeConverter, ConfigurationValidatorBase validator, ConfigurationPropertyOptions options, string description)
  70.         {
  71.             ConstructorInit(name, type, options, validator, typeConverter);
  72.            
  73.             SetDefaultValue(defaultValue);
  74.         }
  75.        
  76.         internal ConfigurationProperty(PropertyInfo info)
  77.         {
  78.             Debug.Assert(info != null, "info != null");
  79.            
  80.             // Bellow are the attributes we handle
  81.             TypeConverterAttribute attribConverter = null;
  82.             ConfigurationPropertyAttribute attribProperty = null;
  83.             ConfigurationValidatorAttribute attribValidator = null;
  84.            
  85.             // Compatability attributes
  86.             // If the approprite data is provided in the ConfigPropAttribute then the one bellow will be ignored
  87.             DescriptionAttribute attribStdDescription = null;
  88.             DefaultValueAttribute attribStdDefault = null;
  89.            
  90.             TypeConverter typeConverter = null;
  91.             ConfigurationValidatorBase validator = null;
  92.            
  93.             // Find the interesting attributes in the collection
  94.             foreach (Attribute attribute in Attribute.GetCustomAttributes(info)) {
  95.                 if (attribute is TypeConverterAttribute) {
  96.                     attribConverter = (TypeConverterAttribute)attribute;
  97.                     typeConverter = (TypeConverter)TypeUtil.CreateInstanceWithReflectionPermission(attribConverter.ConverterTypeName);
  98.                 }
  99.                 else if (attribute is ConfigurationPropertyAttribute) {
  100.                     attribProperty = (ConfigurationPropertyAttribute)attribute;
  101.                 }
  102.                 else if (attribute is ConfigurationValidatorAttribute) {
  103.                    
  104.                     if (validator != null) {
  105.                         throw new ConfigurationErrorsException(SR.GetString(SR.Validator_multiple_validator_attributes, info.Name));
  106.                     }
  107.                    
  108.                     attribValidator = (ConfigurationValidatorAttribute)attribute;
  109.                     validator = attribValidator.ValidatorInstance;
  110.                 }
  111.                 else if (attribute is DescriptionAttribute) {
  112.                     attribStdDescription = (DescriptionAttribute)attribute;
  113.                 }
  114.                 else if (attribute is DefaultValueAttribute) {
  115.                     attribStdDefault = (DefaultValueAttribute)attribute;
  116.                 }
  117.                
  118.             }
  119.            
  120.             Type propertyType = info.PropertyType;
  121.             // Collections need some customization when the collection attribute is present
  122.             if (typeof(ConfigurationElementCollection).IsAssignableFrom(propertyType)) {
  123.                 ConfigurationCollectionAttribute attribCollection = Attribute.GetCustomAttribute(info, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
  124.                
  125.                 // If none on the property - see if there is an attribute on the collection type itself
  126.                 if (attribCollection == null) {
  127.                     attribCollection = Attribute.GetCustomAttribute(propertyType, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
  128.                 }
  129.                 if (attribCollection != null) {
  130.                     if (attribCollection.AddItemName.IndexOf(',') == -1) {
  131.                         _addElementName = attribCollection.AddItemName;
  132.                     }
  133.                     _removeElementName = attribCollection.RemoveItemName;
  134.                     _clearElementName = attribCollection.ClearItemsName;
  135.                    
  136.                 }
  137.                
  138.             }
  139.            
  140.             // This constructor shouldnt be invoked if the reflection info is not for an actual config property
  141.             Debug.Assert(attribProperty != null, "attribProperty != null");
  142.            
  143.             ConstructorInit(attribProperty.Name, info.PropertyType, attribProperty.Options, validator, typeConverter);
  144.            
  145.             // Figure out the default value
  146.             InitDefaultValueFromTypeInfo(attribProperty, attribStdDefault);
  147.            
  148.             // Get the description
  149.             if ((attribStdDescription != null) && !string.IsNullOrEmpty(attribStdDescription.Description)) {
  150.                 _description = attribStdDescription.Description;
  151.             }
  152.         }
  153.        
  154.         private void ConstructorInit(string name, Type type, ConfigurationPropertyOptions options, ConfigurationValidatorBase validator, TypeConverter converter)
  155.         {
  156.             if (typeof(ConfigurationSection).IsAssignableFrom(type)) {
  157.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_properties_may_not_be_derived_from_configuration_section, name));
  158.             }
  159.            
  160.             _providedName = name;
  161.             // save the provided name so we can check for default collection names
  162.             if ((options & ConfigurationPropertyOptions.IsDefaultCollection) != 0 && String.IsNullOrEmpty(name)) {
  163.                 name = DefaultCollectionPropertyName;
  164.             }
  165.             else {
  166.                 ValidatePropertyName(name);
  167.             }
  168.            
  169.             _name = name;
  170.             _type = type;
  171.             _options = options;
  172.             _validator = validator;
  173.             _converter = converter;
  174.            
  175.             // Use the default validator if none was supplied
  176.             if (_validator == null) {
  177.                 _validator = DefaultValidatorInstance;
  178.             }
  179.             else {
  180.                 // Make sure the supplied validator supports the type of this property
  181.                 if (!_validator.CanValidate(_type)) {
  182.                     throw new ConfigurationErrorsException(SR.GetString(SR.Validator_does_not_support_prop_type, _name));
  183.                 }
  184.             }
  185.         }
  186.        
  187.         private void ValidatePropertyName(string name)
  188.         {
  189.             if (string.IsNullOrEmpty(name)) {
  190.                 throw new ArgumentException(SR.GetString(SR.String_null_or_empty), "name");
  191.             }
  192.            
  193.             if (BaseConfigurationRecord.IsReservedAttributeName(name)) {
  194.                 throw new ArgumentException(SR.GetString(SR.Property_name_reserved, name));
  195.             }
  196.         }
  197.        
  198.         private void SetDefaultValue(object value)
  199.         {
  200.             // Validate the default value if any. This should make errors from invalid defaults easier to catch
  201.             if (value != null && value != ConfigurationElement.s_nullPropertyValue) {
  202.                 bool canAssign = _type.IsAssignableFrom(value.GetType());
  203.                 if (!canAssign && this.Converter.CanConvertFrom(value.GetType())) {
  204.                     value = this.Converter.ConvertFrom(value);
  205.                 }
  206.                 else if (!canAssign) {
  207.                     throw new ConfigurationErrorsException(SR.GetString(SR.Default_value_wrong_type, _name));
  208.                 }
  209.                
  210.                 Validate(value);
  211.                
  212.                 _defaultValue = value;
  213.             }
  214.         }
  215.        
  216.         private void InitDefaultValueFromTypeInfo(ConfigurationPropertyAttribute attribProperty, DefaultValueAttribute attribStdDefault)
  217.         {
  218.             object defaultValue = attribProperty.DefaultValue;
  219.            
  220.             // If there is no default value there - try the other attribute ( the clr standard one )
  221.             if ((defaultValue == null || defaultValue == ConfigurationElement.s_nullPropertyValue) && (attribStdDefault != null)) {
  222.                 defaultValue = attribStdDefault.Value;
  223.             }
  224.            
  225.             // If there was a default value in the prop attribute - check if we need to convert it from string
  226.             if ((defaultValue != null) && (defaultValue is string) && (_type != typeof(string))) {
  227.                 // Use the converter to parse this property default value
  228.                 try {
  229.                     defaultValue = Converter.ConvertFromInvariantString((string)defaultValue);
  230.                 }
  231.                 catch (Exception ex) {
  232.                     throw new ConfigurationErrorsException(SR.GetString(SR.Default_value_conversion_error_from_string, _name, ex.Message));
  233.                 }
  234.                 catch {
  235.                     throw new ConfigurationErrorsException(SR.GetString(SR.Default_value_conversion_error_from_string, _name, ExceptionUtil.NoExceptionInformation));
  236.                 }
  237.             }
  238.             if (defaultValue == null || defaultValue == ConfigurationElement.s_nullPropertyValue) {
  239.                 if (_type == typeof(string)) {
  240.                     defaultValue = String.Empty;
  241.                 }
  242.                 else if (_type.IsValueType) {
  243.                     defaultValue = TypeUtil.CreateInstanceWithReflectionPermission(_type);
  244.                 }
  245.             }
  246.             SetDefaultValue(defaultValue);
  247.         }
  248.        
  249.         public string Name {
  250.             get { return _name; }
  251.         }
  252.        
  253.         public string Description {
  254.             get { return _description; }
  255.         }
  256.        
  257.         internal string ProvidedName {
  258.             get { return _providedName; }
  259.         }
  260.        
  261.         public Type Type {
  262.             get { return _type; }
  263.         }
  264.        
  265.         public object DefaultValue {
  266.             get { return _defaultValue; }
  267.         }
  268.        
  269.         public bool IsRequired {
  270.             get { return (_options & ConfigurationPropertyOptions.IsRequired) != 0; }
  271.         }
  272.        
  273.         public bool IsKey {
  274.             get { return (_options & ConfigurationPropertyOptions.IsKey) != 0; }
  275.         }
  276.        
  277.         public bool IsDefaultCollection {
  278.             get { return ((_options & ConfigurationPropertyOptions.IsDefaultCollection) != 0); }
  279.         }
  280.        
  281.        
  282.         public TypeConverter Converter {
  283.             get {
  284.                 CreateConverter();
  285.                
  286.                 return _converter;
  287.             }
  288.         }
  289.        
  290.         public ConfigurationValidatorBase Validator {
  291.             get { return _validator; }
  292.         }
  293.        
  294.         internal string AddElementName {
  295.             get { return _addElementName; }
  296.         }
  297.         internal string RemoveElementName {
  298.             get { return _removeElementName; }
  299.         }
  300.         internal string ClearElementName {
  301.             get { return _clearElementName; }
  302.         }
  303.        
  304.         internal object ConvertFromString(string value)
  305.         {
  306.             object result = null;
  307.            
  308.             try {
  309.                 result = Converter.ConvertFromInvariantString(value);
  310.             }
  311.             catch (Exception ex) {
  312.                 throw new ConfigurationErrorsException(SR.GetString(SR.Top_level_conversion_error_from_string, _name, ex.Message));
  313.             }
  314.             catch {
  315.                 throw new ConfigurationErrorsException(SR.GetString(SR.Top_level_conversion_error_from_string, _name, ExceptionUtil.NoExceptionInformation));
  316.             }
  317.            
  318.             return result;
  319.         }
  320.        
  321.         internal string ConvertToString(object value)
  322.         {
  323.             string result = null;
  324.            
  325.             try {
  326.                 if (_type == typeof(bool)) {
  327.                     result = ((bool)value) ? "true" : "false";
  328.                     // the converter will break 1.1 compat for bool
  329.                 }
  330.                 else {
  331.                     result = Converter.ConvertToInvariantString(value);
  332.                 }
  333.             }
  334.             catch (Exception ex) {
  335.                 throw new ConfigurationErrorsException(SR.GetString(SR.Top_level_conversion_error_to_string, _name, ex.Message));
  336.             }
  337.             catch {
  338.                 throw new ConfigurationErrorsException(SR.GetString(SR.Top_level_conversion_error_to_string, _name, ExceptionUtil.NoExceptionInformation));
  339.             }
  340.            
  341.             return result;
  342.         }
  343.         internal void Validate(object value)
  344.         {
  345.             try {
  346.                 _validator.Validate(value);
  347.             }
  348.             catch (Exception ex) {
  349.                 throw new ConfigurationErrorsException(SR.GetString(SR.Top_level_validation_error, _name, ex.Message), ex);
  350.             }
  351.             catch {
  352.                 throw new ConfigurationErrorsException(SR.GetString(SR.Top_level_validation_error, _name, ExceptionUtil.NoExceptionInformation));
  353.             }
  354.         }
  355.         private void CreateConverter()
  356.         {
  357.             // Some properties cannot have type converters.
  358.             // Such examples are properties that are ConfigurationElement ( derived classes )
  359.             // or properties which are user-defined and the user code handles serialization/desirialization so
  360.             // the property itself is never converted to/from string
  361.            
  362.             if (_converter == null) {
  363.                 // Enums are exception. We use our custom converter for all enums
  364.                 if (_type.IsEnum) {
  365.                     _converter = new GenericEnumConverter(_type);
  366.                 }
  367.                 else if (!_type.IsSubclassOf(typeof(ConfigurationElement))) {
  368.                     _converter = TypeDescriptor.GetConverter(_type);
  369.                    
  370.                     if ((_converter == null) || !_converter.CanConvertFrom(typeof(string)) || !_converter.CanConvertTo(typeof(string))) {
  371.                         throw new ConfigurationErrorsException(SR.GetString(SR.No_converter, _name, _type.Name));
  372.                     }
  373.                 }
  374.             }
  375.         }
  376.     }
  377. }

Developer Fusion