error saving custom validator in e.l. configuration

Topics: Validation Application Block
Oct 21, 2011 at 3:31 PM

Hello,

I've created a custom validator with the classes needed so that I can use it in the Enterprise Library Configuration tool.(The attribute and data classes). Copied the dll to the bin folder of the tool and the validator shows up if I right click and select add validator. The extra properties I added show up and I can fill them with values. However when I try to save the config file in the Configuration tool I get this error:

"The application could not save the configuration information to the configuration file. Please try to save the configuration to a different file. Error message: An error occurred executing the configuration section handler for validation"

Checked my customvalidator,, customvalidatorattribute and customvalidatordata classes multiple times and compared them with tutorials on the net and couldn't find anything wrong in the code. And I can use my validator in the config tool, only cant save.

I've googled and searched but can't find any clue or solution for this problem I'm having. Anyone have an idea about what might be causing this error?

Thanks in advance,

sophia

Oct 22, 2011 at 7:34 AM
Edited Oct 22, 2011 at 7:35 AM

Hi Sophia,

I couldn't recreate your issue.  Can you post your code?  What version are you using?

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com

Oct 24, 2011 at 8:51 AM
 

MY Custom Validator:

/// <summary>
	/// Validator for string length
	/// </summary>
	[ConfigurationElementType( typeof( StringLengthValidatorData ) )]
	public class StringLengthValidator : ValueValidator<string>
	{

		#region Variables


		/// <summary>
		/// Variable to set if it allowed that the value is empty or null
		/// </summary>
		private bool _isAllowedEmpty;

		/// <summary>
		/// Min value that string's length need to be 
		/// </summary>
		private int _minLength;

		/// <summary>
		/// Max value that string's length needs to be
		/// </summary>
		private int _maxLength;

		/// <summary>
		/// IFormatProvider for setting locale
		/// </summary>
		private IFormatProvider _culture = new CultureInfo( CultureInfo.CurrentCulture.ToString(), true );

		#endregion
		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="collection">The name value collection</param>
		public StringLengthValidator( NameValueCollection collection )
			: base( string.Empty, string.Empty, false )
		{
			this.IsAllowedEmpty = Convert.ToBoolean( collection.Get( "IsAllowedEmpty" ), _culture );
			this.MinLength = Convert.ToInt32( collection.Get( "MinLength" ).ToString(), _culture );
			this.MaxLength = Convert.ToInt32( collection.Get( "MaxLength" ).ToString(), _culture );
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="minValue">Integer min length </param>	
		/// <param name="maxValue">Interger max length</param>
		/// <param name="isAllowEmpty">Bool if string is allowed to be empty or null</param>
		/// <param name="messageTemplate">String messageTemplate</param>
		/// <param name="negated">Bool negated</param>
		public StringLengthValidator( int minValue, int maxValue, bool isAllowEmpty, string messageTemplate, bool negated )
			: base( messageTemplate, null, negated )
		{
			this.MinLength = minValue;
			this.MaxLength = maxValue;
			this.IsAllowedEmpty = isAllowEmpty;
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="data">StringLengthValidatorData </param>
		public StringLengthValidator( StringLengthValidatorData data )
			: this( data.MinLength, data.MaxLength, data.IsAllowedEmpty, data.MessageTemplate, data.Negated )
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="minValue">Integer min length </param>
		/// <param name="maxLength">Integer max length</param>
		/// <param name="isAllowedEmpty">Bool if string is allowed to be empty or null</param>
		public StringLengthValidator( int minValue, int maxLength, bool isAllowedEmpty )
			: base( string.Empty, null, false )
		{
			this.MinLength = minValue;
			this.MaxLength = maxLength;
			this.IsAllowedEmpty = isAllowedEmpty;
		}


		#endregion

		#region Properties
		/// <summary>
		/// Property if string can be empty or null
		/// </summary>
		public bool IsAllowedEmpty
		{
			get
			{
				return _isAllowedEmpty;
			}
			set
			{
				if( value != _isAllowedEmpty )
				{
					_isAllowedEmpty = value;

				}
			}
		}

		/// <summary>
		/// Property with the maxlength the string is allowed to be
		/// </summary>
		public int MaxLength
		{
			get
			{
				return _maxLength;
			}
			set
			{
				if( value != _maxLength )
				{
					_maxLength = value;
				}
			}
		}

		/// <summary>
		/// Property with the min length that the value needs to be
		/// </summary>
		public int MinLength
		{
			get
			{
				return _minLength;
			}
			set
			{
				if( value != _minLength )
				{
					_minLength = value;
				}
			}
		}

		/// <summary>
		/// MessageTemplate, should not use prop
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "Application should not use this property" )]
		protected override string DefaultNegatedMessageTemplate
		{
			get
			{
				return Resources.StringLengthValidatorNegatedDefaultMessageTemplate; 
			}
		}
		/// <summary>
		/// DefaultNonNegatedMessageTemplate, should not use prop
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "Application should not use this property" )]
		protected override string DefaultNonNegatedMessageTemplate
		{
			get
			{
				return Resources.StringLengthValidatorNegatedDefaultMessageTemplate; 
			}
		}

		#endregion

		#region Protected methods

		/// <summary>
		/// Implements the validation logic for the receiver. 
		/// </summary>
		/// <param name="objectToValidate">The decimal object to validate.</param>
		/// <param name="currentTarget">The object on the behalf of which the validation is performed.</param>
		/// <param name="key">The key that identifies the source of objectToValidate.</param>
		/// <param name="validationResults">The validation results to which the outcome of the validation should be stored.</param>
		protected override void DoValidate( string objectToValidate, object currentTarget, string key, ValidationResults validationResults )
		{
			try
			{
				if( !IsAllowedEmpty && objectToValidate.Equals( null ) )
				{
					LogValidationResult( validationResults, GetErrorMessage( "verplicht" ), currentTarget, key );
				}
				else if( !IsAllowedEmpty && objectToValidate.Length == 0 )
				{
					LogValidationResult( validationResults, GetErrorMessage( "verplicht" ), currentTarget, key );
				}
				else
				{
					if( objectToValidate.Length < MinLength && objectToValidate.Length > MaxLength )
					{
						LogValidationResult( validationResults, GetErrorMessage( "ongeldig" ), currentTarget, key );
					}
					else if( objectToValidate.Length < MinLength )
					{
						LogValidationResult( validationResults, GetErrorMessage( "tekort" ), currentTarget, key );
					}
					else if( objectToValidate.Length > MinLength )
					{
						LogValidationResult( validationResults, GetErrorMessage( "telang" ), currentTarget, key );
					}
				}
			}
			catch( ArgumentNullException )
			{
				LogValidationResult( validationResults, GetErrorMessage( "ongeldig" ), currentTarget, key );
			}
			catch( FormatException )
			{
				LogValidationResult( validationResults, GetErrorMessage( "ongeldig" ), currentTarget, key );
			}
			catch( OverflowException )
			{
				LogValidationResult( validationResults, GetErrorMessage( "ongeldig" ), currentTarget, key );
			}
		}
		#endregion
		#region private methods
		/// <summary>
		/// Get the error message from resource file
		/// </summary>
		/// <param name="error">String error</param>
		/// <returns>String errormessage</returns>
		private static string GetErrorMessage( string error )
		{
			//get error value from stringresource file
			Assembly assembly = Assembly.GetExecutingAssembly();
			ResourceManager resmgr = new ResourceManager( "Vertimart.Exquise.DomainObjects.StringResource", assembly );
			switch( error )
			{
				case "ongeldig":
					return resmgr.GetString( "Algemeen_Ongeldig_String", CultureInfo.CurrentCulture );
				case "verplicht":
					return resmgr.GetString( "Algemeen_Ongeldig_Verplicht", CultureInfo.CurrentCulture );
				case "tekort":
					return resmgr.GetString( "Algemeen_Ongeldig_String_Tekort", CultureInfo.CurrentCulture );
				case "telang":
					return resmgr.GetString( "Algemeen_Ongeldig_String_Telang", CultureInfo.CurrentCulture );
			}
			return string.Empty;
		}
		#endregion
	}
}

 

My ValidatorAttribute:

 

/// <summary>
	/// Represents a <see cref="StringLengthValidatorAttribute"/>.
	/// </summary>
	[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments", Justification = "Fields are used internally" ), AttributeUsage( AttributeTargets.Property
		| AttributeTargets.Parameter,
		AllowMultiple = true,
		Inherited = false )]
	public sealed class StringLengthValidatorAttribute : ValueValidatorAttribute
	{
		#region variabelen
		/// <summary>
		/// Max length of the string
		/// </summary>
		private int _maxLength;
		/// <summary>
		/// Min length of the string
		/// </summary>
		private int _minLength;
		/// <summary>
		/// Boolean if the string if allowed to be empty
		/// </summary>
		private bool _isAllowedEmpty;
		#endregion
		#region constructors
		/// <summary>
		/// <para>Initializes a new instance of the <see cref="StringLengthValidatorAttribute"/>.</para>
		/// </summary>
		public StringLengthValidatorAttribute()
		{
		}

		/// <summary>
		/// <para>Initializes a new instance of the <see cref="StringLengthValidatorAttribute"/>.</para>
		/// </summary>
		/// <param name="minLength">Integer Mininum length of the string</param>
		/// <param name="maxLength">Integer Maximum length of the string</param>
		/// <param name="isAllowedEmpty">Bool is the string is allowed to be empty or null</param>
		public StringLengthValidatorAttribute( int minLength, int maxLength, bool isAllowedEmpty )
		{
			_minLength = minLength;
			_maxLength = maxLength;
			_isAllowedEmpty = isAllowedEmpty;
		}
		#endregion

		#region protected methods
		/// <summary>
		/// Creates the <see cref="StringLengthValidator"/> described by the attribute object.
		/// </summary>
		/// <param name="targetType">The type of object that will be validated by the validator.</param>
		/// <remarks>This operation must be overriden by subclasses.</remarks>
		/// <returns>The created <see cref="StringLengthValidator"/>.</returns>
		protected override Validator DoCreateValidator( Type targetType )
		{
			return new StringLengthValidator( this._minLength, this._maxLength, this._isAllowedEmpty, MessageTemplate, Negated );
		}
		#endregion
	}
My validator Data:
/// <summary>
	/// Test
	/// </summary>
	[ResourceDescription(typeof( Resources ), "StringLengthValidatorDataDescription")]
	[ResourceDisplayName( typeof( Resources ), "StringLengthValidatorDataDisplayName" )]
	public class StringLengthValidatorData : ValueValidatorData
	{
		#region variables
		/// <summary>
		/// Constante naam for minimum lengte
		/// </summary>
		private const string _minValuePropertyName = "Minimale lengte";
		/// <summary>
		/// Constante naam for maximum lengte
		/// </summary>
		private const string _maxValuePropertyName = "Maximale lengte";
		/// <summary>
		/// Constante naam for isAllowedEmpty
		/// </summary>
		private const string _isAllowedEmptyPropertyName = "Mag leeg zijn";
		#endregion

		#region constructor
		/// <summary>
		/// Constructor 
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification="Code is like in tutorial" )]
		public StringLengthValidatorData()
		{
			this.Type = typeof( StringLengthValidator );
		}
		/// <summary>
		/// Constructor with parameter name of the instance
		/// </summary>
		/// <param name="name">Name for the instance</param>
		public StringLengthValidatorData( string name )
			: base( name, typeof( StringLengthValidator ) )
		{
		}

		/// <summary>
		/// Constructor with all parameters
		/// </summary>
		/// <param name="name">String name</param>
		/// <param name="minLength">Integer min length for string</param>
		/// <param name="maxLength">Integer max length for string</param>
		/// <param name="isAllowedEmpty">Boolean if empty is allowed for string</param>
		public StringLengthValidatorData(string name, int minLength, int maxLength, bool isAllowedEmpty)
		:base(name, typeof(StringLengthValidator))
		{
			MinLength = minLength;
			MaxLength = maxLength;
			IsAllowedEmpty = isAllowedEmpty;
		}


		#endregion

		#region properties
		/// <summary>
		/// Propertie minlength
		/// </summary>
		[ConfigurationProperty( _minValuePropertyName, IsRequired = true,
						DefaultValue = 0 )]
		[ResourceDescription( typeof( Resources ), "StringLengthValidatorData_DisplayDescription_MinLength" )]
		[ResourceDisplayName( typeof( Resources ), "StringLengthValidatorData_DisplayName_MinLength" )]
		public int MinLength
		{
			get
			{
				return ( int )this[ _minValuePropertyName ];
			}
			set
			{
				this[ _minValuePropertyName ] = value;
			}
		}
		/// <summary>
		/// Propertie maxLength
		/// </summary>
		[ConfigurationProperty( _maxValuePropertyName, IsRequired = true,
						DefaultValue = 0 )]
		[ResourceDescription( typeof( Resources ), "StringLengthValidatorData_DisplayDescription_MaxLength" )]
		[ResourceDisplayName( typeof( Resources ), "StringLengthValidatorData_DisplayName_MaxLength" )]
		public int MaxLength
		{
			get
			{
				return ( int )this[ _maxValuePropertyName ];
			}
			set
			{
				this[ _maxValuePropertyName ] = value;
			}
		}
		/// <summary>
		/// Propertie is string is allowed to be mepty or null
		/// </summary>
		[ConfigurationProperty( _isAllowedEmptyPropertyName, IsRequired = true,
						DefaultValue = true )]
		[ResourceDescription( typeof( Resources ), "StringLengthValidatorData_DisplayDescription_IsAllowedEmpty" )]
		[ResourceDisplayName( typeof( Resources ), "StringLengthValidatorData_DisplayName_IsAllowedEmpty" )]
		public bool IsAllowedEmpty
		{
			get
			{
				return ( bool )this[ _isAllowedEmptyPropertyName ];
			}
			set
			{
				this[ _isAllowedEmptyPropertyName ] = value;
			}
		}
		#endregion
		/// <summary>
		/// Creates the <see cref="StringLengthValidator"/> described by the configuration object.
		/// </summary>
		/// <param name="targetType">The type of object that will be validated by the validator.</param>
		/// <returns>The created <see cref="StringLengthValidator"/>.</returns>	
		protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator( Type targetType )
		{
			return new StringLengthValidator(this);
		}

	}


Then I build the project, copy the dll in the bin of the enterprise library. Open the config file with enterprise library v5 configuration. add my validator, (it comes up on the validator menu,so it's working),
 but when I try to save the config file I get the errormessage "The application could not save the configuration information to the configuration file.
 Please try to save the configuration to a different file. Error message: An error occurred executing the configuration section handler for validation"
Use enterprise library 5, project is .net framework 4.
Hope you can help, thanks in advance.
Oct 25, 2011 at 7:36 AM

OK, I see what's going on.  It's a bit tricky but sort of obvious when you think about it.

You have defined your property names as:

#region variables
/// <summary>
/// Constante naam for minimum lengte
/// </summary>
private const string _minValuePropertyName = "Minimale lengte";
/// <summary>
/// Constante naam for maximum lengte
/// </summary>
private const string _maxValuePropertyName = "Maximale lengte";
/// <summary>
/// Constante naam for isAllowedEmpty
/// </summary>
private const string _isAllowedEmptyPropertyName = "Mag leeg zijn";
#endregion

The problem is that these are used as attribute names in the XML config.  The problem with that is that XML attribute names cannot contain a space.

The easy work around is to substitute an underscore for a space:

#region variables
/// <summary>
/// Constante naam for minimum lengte
/// </summary>
private const string _minValuePropertyName = "Minimale_lengte";
/// <summary>
/// Constante naam for maximum lengte
/// </summary>
private const string _maxValuePropertyName = "Maximale_lengte";
/// <summary>
/// Constante naam for isAllowedEmpty
/// </summary>
private const string _isAllowedEmptyPropertyName = "Mag_leeg_zijn";
#endregion

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com

Oct 25, 2011 at 8:17 AM

It works now, thank you so much :)

Oct 26, 2011 at 12:46 AM

Great to hear!

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com