Custom Validator with Full Configuration Integration fails

Topics: Building and extending application blocks, Validation Application Block
Sep 17, 2010 at 7:52 AM

Hi all,

I was trying to implement my own custom validator with Full Configuration Integration, as explained in:

http://msdn.microsoft.com/en-us/library/ff664540(v=PandP.50).aspx

and in Hands On Labs (5/24 release), Lab 11\After.

The problem is that when I load the new Validator in the Ent. Lib. Configuration Tool, right-clicking on Validator and then Add Validator, I correctly find and then add my custom validator.

The next time, if I try to reopen the config file, the new validator shows up as if it was a simple Custom Validator.

Sep 17, 2010 at 4:21 PM

Hi gsaielli,

How are you opening up your config file? Are you sure you're using the right configuration tool where you have put the ValidationHOL.CustomValidators.dll in the same directory of the config tool? Don't get confuse with the VS integrated config tool since the Lab11 solution EntLib Assembly Set is defaulted to point in the Enttlib installation folder (machine default). While the Lab11 instruction is to put the ValidationHOL.CustomValidators.dll in the Hands On Lab Lib folder. Hope this somehow helps.

Gino Terrado
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

 

Sep 20, 2010 at 12:40 PM

Hi Gino,

no, it doesn't work, and since I spent very much time trying to solve it, I feel quite sure this must be a bug.

Otherwise, can you just post a simple case of Custom Validator with full configuration?

Thank you very much for your help,

gsa

 

Sep 21, 2010 at 11:27 AM

Hmm weird I just got it working last week and now not even sure why it is not working. I actually got a copy of the working assembly in my PC, though still don't know why it is not working in a newly compiled assembly of LAB11. Anyway, for a sample of full integration of a custom validator you can check this blog and download a sample from it. Though, it still uses an old entlib version so you need to update its reference if you're using the latest. Basically, the most important component you need for the full integration are the PersonIDValidator.cs and PersonIDValidatorData.cs class. Compile and build the project, deploy the assembly in the same directory of the EntLib Config tool you're going to use and that should be it. You should be able to see the new validator included in the Validator list of the Validation App Block. HTH

PersonIDValidatorData.cs

 

using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;

    /// <summary>
    /// Represents the configuration data for a <see cref="PersonIDValidator"/>.
    /// </summary>	
    public class PersonIDValidatorData : ValueValidatorData
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ValueValidatorData"/> class.
        /// </summary>
        public PersonIDValidatorData()
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="ValueValidatorData"/> class.
        /// </summary>
        /// <param name="name">The name for the instance.</param>
        public PersonIDValidatorData(string name)
            : base(name, typeof(PersonIDValidator))
        { }

        /// <summary>
        /// Creates the <see cref="PersonIDValidator"/> 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="PersonIDValidator"/>.</returns>	
        protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator(Type targetType)
        {
            return new PersonIDValidator(this);
        }

        // TODO: Add the configuration properties for PersonIDValidatorData. The snippet for creating configuration properties would be useful.
        private const string CountryCodePropertyName = "CountryCode";
        [ConfigurationProperty(CountryCodePropertyName)]
        public int CountryCode
        {
            get { return (int)this[CountryCodePropertyName]; }
            set { this[CountryCodePropertyName] = value; }
        }
}

 

PersonIDValidator.cs

using Bursteg.ProvidersLibrary.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;


    /// <summary>
    /// TODO: Add PersonIDValidator comment.
    /// </summary>
    [ConfigurationElementType(typeof(PersonIDValidatorData))]
    public class PersonIDValidator : ValueValidator
    {
        private int countryCode;

        public int CountryCode
        {
            get { return countryCode; }
            set { countryCode = value; }
        }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="configuration">The configuration instance for the validator.</param>
        public PersonIDValidator(PersonIDValidatorData configuration)
            : this(configuration.CountryCode, configuration.MessageTemplate, configuration.Negated)
        {
        }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        public PersonIDValidator(int country)
            : this(country, null, false)
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        /// <param name="negated">True if the validator must negate the result of the validation.</param>
        public PersonIDValidator(int country, bool negated)
            : this(country, null, negated)
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        /// <param name="messageTemplate">The message template to use when logging results.</param>
        public PersonIDValidator(int country, string messageTemplate)
            : this(country, messageTemplate, false)
        { }

        // <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        /// <param name="messageTemplate">The message template to use when logging results.</param>
        /// <param name="negated">True if the validator must negate the result of the validation</param>
        public PersonIDValidator(int coutry, string messageTemplate, bool negated)
            : base(messageTemplate, null, negated)
        {
            this.countryCode = coutry;
        }

        /// <summary>
        /// Gets the Default Message Template when the PersonIDValidator validator is non negated.
        /// </summary>
        protected override string DefaultNonNegatedMessageTemplate
        {
            get { return Bursteg.ProvidersLibrary.Properties.Resources.PersonIDValidatorNonNegatedDefaultMessage; }
        }

        /// <summary>
        /// Gets the Default Message Template when the PersonIDValidator validator is negated.
        /// </summary>
        protected override string DefaultNegatedMessageTemplate
        {
            get { return Bursteg.ProvidersLibrary.Properties.Resources.PersonIDValidatorNegatedDefaultMessage; }
        }


        /// <summary>
        /// Implements the validation logic for the receiver.
        /// </summary>
        /// <param name="objectToValidate">The 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 <paramref name="objectToValidate"/>.</param>
        /// <param name="validationResults">The validation results to which the outcome of the validation should be stored.</param>
        
        
        public override void DoValidate(object objectToValidate, object currentTarget, string key, Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults validationResults)
        {
            // Get the object to validate
            string id = (string)objectToValidate;

            // Check if it is valid
            string end = countryCode.ToString().Trim();
            bool isValid = id.EndsWith(end);

            // If the negated property is false, and the id is not valid, log a validation error
            if (isValid == Negated)
            {
                LogValidationResult(validationResults, this.MessageTemplate, currentTarget, key);
            }
        }
}

Gino Terrado
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Sep 22, 2010 at 1:31 AM
Edited Sep 22, 2010 at 1:59 AM

 This looks like a bug.  We'll continue looking at this.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Sep 22, 2010 at 7:12 AM
Thanks Gino. Well, from a quick look the article you mentioned (which I previously found in many other places on the Internet) is really outdated. Not only it refers to 3.1 version of EntLib, and to VS 2005, but also to assemblies no more present in the Entlib. So it's difficult (and not worth) to convert...
 
I think we need a much simple sample of a Custom Validator with full configuration support: a couple of files, as explained in Lab 11, and we see if it works or not (as I suspect).
 
Thank you very much.
gsaielli 

 
2010/9/21 AvanadeSupport <notifications@codeplex.com>

From: AvanadeSupport

Hmm weird I just got it working last week and now not even sure why it is not working. I actually got a copy of the working assembly in my PC, though still don't know why it is not working in a newly compiled assembly of LAB11. Anyway, for a sample of full integration of a custom validator you can check this blog and download a sample from it. Though, it still uses an old entlib version so you need to update its reference if you're using the latest. Basically, the most important component you need for the full integration are the PersonIDValidator.cs and PersonIDValidatorData.cs class. Compile and build the project, deploy the assembly in the same directory of the EntLib Config tool you're going to use and that should be it. You should be able to see the new validator included in the Validator list of the Validation App Block. HTH

PersonIDValidatorData.cs

 

using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;

    /// <summary>
    /// Represents the configuration data for a <see cref="PersonIDValidator"/>.
    /// </summary>	
    public class PersonIDValidatorData : ValueValidatorData
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ValueValidatorData"/> class.
        /// </summary>
        public PersonIDValidatorData()
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="ValueValidatorData"/> class.
        /// </summary>
        /// <param name="name">The name for the instance.</param>
        public PersonIDValidatorData(string name)
            : base(name, typeof(PersonIDValidator))
        { }

        /// <summary>
        /// Creates the <see cref="PersonIDValidator"/> 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="PersonIDValidator"/>.</returns>	
        protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator(Type targetType)
        {
            return new PersonIDValidator(this);
        }

        // TODO: Add the configuration properties for PersonIDValidatorData. The snippet for creating configuration properties would be useful.
        private const string CountryCodePropertyName = "CountryCode";
        [ConfigurationProperty(CountryCodePropertyName)]
        public int CountryCode
        {
            get { return (int)this[CountryCodePropertyName]; }
            set { this[CountryCodePropertyName] = value; }
        }
}

 

PersonIDValidator.cs

using Bursteg.ProvidersLibrary.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;


    /// <summary>
    /// TODO: Add PersonIDValidator comment.
    /// </summary>
    [ConfigurationElementType(typeof(PersonIDValidatorData))]
    public class PersonIDValidator : ValueValidator
    {
        private int countryCode;

        public int CountryCode
        {
            get { return countryCode; }
            set { countryCode = value; }
        }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="configuration">The configuration instance for the validator.</param>
        public PersonIDValidator(PersonIDValidatorData configuration)
            : this(configuration.CountryCode, configuration.MessageTemplate, configuration.Negated)
        {
        }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        public PersonIDValidator(int country)
            : this(country, null, false)
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        /// <param name="negated">True if the validator must negate the result of the validation.</param>
        public PersonIDValidator(int country, bool negated)
            : this(country, null, negated)
        { }

        /// <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        /// <param name="messageTemplate">The message template to use when logging results.</param>
        public PersonIDValidator(int country, string messageTemplate)
            : this(country, messageTemplate, false)
        { }

        // <summary>
        /// <para>Initializes a new instance of the <see cref="PersonIDValidator"/>.</para>
        /// </summary>
        /// <param name="coutry">Country Code to validate by it</param>
        /// <param name="messageTemplate">The message template to use when logging results.</param>
        /// <param name="negated">True if the validator must negate the result of the validation</param>
        public PersonIDValidator(int coutry, string messageTemplate, bool negated)
            : base(messageTemplate, null, negated)
        {
            this.countryCode = coutry;
        }

        /// <summary>
        /// Gets the Default Message Template when the PersonIDValidator validator is non negated.
        /// </summary>
        protected override string DefaultNonNegatedMessageTemplate
        {
            get { return Bursteg.ProvidersLibrary.Properties.Resources.PersonIDValidatorNonNegatedDefaultMessage; }
        }

        /// <summary>
        /// Gets the Default Message Template when the PersonIDValidator validator is negated.
        /// </summary>
        protected override string DefaultNegatedMessageTemplate
        {
            get { return Bursteg.ProvidersLibrary.Properties.Resources.PersonIDValidatorNegatedDefaultMessage; }
        }


        /// <summary>
        /// Implements the validation logic for the receiver.
        /// </summary>
        /// <param name="objectToValidate">The 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 <paramref name="objectToValidate"/>.</param>
        /// <param name="validationResults">The validation results to which the outcome of the validation should be stored.</param>
        
        
        public override void DoValidate(object objectToValidate, object currentTarget, string key, Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults validationResults)
        {
            // Get the object to validate
            string id = (string)objectToValidate;

            // Check if it is valid
            string end = countryCode.ToString().Trim();
            bool isValid = id.EndsWith(end);

            // If the negated property is false, and the id is not valid, log a validation error
            if (isValid == Negated)
            {
                LogValidationResult(validationResults, this.MessageTemplate, currentTarget, key);
            }
        }
}

Gino Terrado
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Read the full discussion online.

To add a post to this discussion, reply to this email (entlib@discussions.codeplex.com)

To start a new discussion for this project, email entlib@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
--
Giuseppe Simone Aielli

5, via De Carolis 40128 Bologna
(+39) 051.054.58.85 (Fisso)
(+39) 329.315.68.21 (Tim)
(+39) 346.151.90.41 (Vodafone)

gsaielli (Skype)
giuseppe@aielli.org (Msn)
gsaielli@gmail.com (Google)

Albo degli Ingengeri della Provincia di Bologna n.6575/B
IEEE Member 41608018
P.IVA 02248411205

www.aielli.net
Sep 22, 2010 at 7:16 AM
I reopened the workitem.
gsaielli

2010/9/22 AvanadeSupport <notifications@codeplex.com>

From: AvanadeSupport

I agree, this looks like a bug.  I suggest you create another workitem for this in the Issue Tracker since I saw that you requested the one you logged before to be closed.  Or if it's possible if you can have it opened again.

 

Sarah Urmeneta


Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Read the full discussion online.

To add a post to this discussion, reply to this email (entlib@discussions.codeplex.com)

To start a new discussion for this project, email entlib@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
--
Giuseppe Simone Aielli

5, via De Carolis 40128 Bologna
(+39) 051.054.58.85 (Fisso)
(+39) 329.315.68.21 (Tim)
(+39) 346.151.90.41 (Vodafone)

gsaielli (Skype)
giuseppe@aielli.org (Msn)
gsaielli@gmail.com (Google)

Albo degli Ingengeri della Provincia di Bologna n.6575/B
IEEE Member 41608018
P.IVA 02248411205

www.aielli.net
Sep 22, 2010 at 8:35 AM
Edited Sep 22, 2010 at 8:53 AM

After debugging, I found out that this happens because the value of the type attribute of the custom validator doesn't get written to the configuration file.  It's not a bug.  To correct this, I added this line in the SSNValidatorData's default constructor:

this.Type = typeof(SSNValidator);

Actually, the way to do this is to call the base's constructor passing the type of validator.   However, the ValueValidatorData has no constructor which only takes the type, it's also expecting a name parameter.  Currently, there's no way for the custom provider to receive it's Name property as documented in the Known Issues so I opted to just assign directly the value of the Type property which is essentially what is being done in the base constructor. 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Sep 23, 2010 at 1:45 AM

Hi gsaielli,

I actually able to convert it to EntLib 5 and to .NET Framework 3.5. If you want the sample drop us a mail (entlib.support@avanade.com) :-)

Gino Terrado
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Sep 23, 2010 at 7:43 AM
Well, this works. Absolutely.
Thank you very much.
gsaielli
2010/9/22 AvanadeSupport <notifications@codeplex.com>

From: AvanadeSupport

After debugging, I found out that this happens because the value of the type attribute of the custom validator doesn't get written to the configuration file.  To resolve this, I added this line in the SSNValidatorData's default constructor:

this.Type = typeof(SSNValidator);

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Read the full discussion online.

To add a post to this discussion, reply to this email (entlib@discussions.codeplex.com)

To start a new discussion for this project, email entlib@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
--
Giuseppe Simone Aielli

5, via De Carolis 40128 Bologna
(+39) 051.054.58.85 (Fisso)
(+39) 329.315.68.21 (Tim)
(+39) 346.151.90.41 (Vodafone)

gsaielli (Skype)
giuseppe@aielli.org (Msn)
gsaielli@gmail.com (Google)

Albo degli Ingengeri della Provincia di Bologna n.6575/B
IEEE Member 41608018
P.IVA 02248411205

www.aielli.net
Sep 23, 2010 at 7:45 AM
Thank you, Gino, but last post from Sarah has solved the problem, for me.
 
Cheers,
gsaielli

2010/9/23 AvanadeSupport <notifications@codeplex.com>

From: AvanadeSupport

Hi gsaielli,

I actually able to convert it to EntLib 5 and to .NET Framework 3.5. If you want the sample drop us a mail (entlib.support@avanade.com) :-)

Gino Terrado


Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Read the full discussion online.

To add a post to this discussion, reply to this email (entlib@discussions.codeplex.com)

To start a new discussion for this project, email entlib@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
--
Giuseppe Simone Aielli

5, via De Carolis 40128 Bologna
(+39) 051.054.58.85 (Fisso)
(+39) 329.315.68.21 (Tim)
(+39) 346.151.90.41 (Vodafone)

gsaielli (Skype)
giuseppe@aielli.org (Msn)
gsaielli@gmail.com (Google)

Albo degli Ingengeri della Provincia di Bologna n.6575/B
IEEE Member 41608018
P.IVA 02248411205

www.aielli.net