"Value to validate is not of expected type" when using ValidationFactory

Topics: Validation Application Block
Jun 21, 2011 at 2:23 PM

I receive the following error when using the ValidationFactory.CreateValidator method to call a custom validator.

"Value to validate is not of the expected type: expected StorerTV.InventoryModule.Entities.StorerTVItemType but got System.String instead."

Here is the factory call:

Validator<StorerTVItemType> itemTypeValidator = ValidationFactory.CreateValidator<StorerTVItemType>("ItemTypeRuleSet");
itemTypeValidator.Validate(this, results);

where my config entry is

  <validation>
    <type assemblyName="StorerTV.InventoryModule.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
      name="StorerTV.InventoryModule.Entities.StorerTVItemType">
      <ruleset name="ItemTypeRuleSet">
        <properties>
          <property name="KeyCode">
            <validator messageTemplate="" messageTemplateResourceName=""
              messageTemplateResourceType="" tag="" type="StorerTV.Validators.ItemTypeUniqueKeyCodeValidator, StorerTV.Validators, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
              name="Custom Validator" />
          </property>
        </properties>
      </ruleset>
    </type>
  </validation>

KeyCode in the case is a string.  If I change the property from "KeyCode" to "SiteId" (which is an int) I get a similar result indicating that the value to validate is not of the expected type (in the case of SiteId, the error reads "Value to validate is not of the expected type: expected StorerTV.InventoryModule.Entities.StorerTVItemType but got System.Int32 instead."). 

What I am not clear about is this: if I declare my validatior to expect a type of StorerTVItemType, how do I tell it that I want to validate the KeyCode property?

I also want to ask if it is possible to pass parameters dynamically to the validator?  I tried to declare public properties on it but was not able to access them because the ValidationFactory.CreateValidator returns a GenericValidatorWrapper class.

Can someone help with this?  If I need to provide more information, please let me know.

Thanks,

Joe

 

Jun 22, 2011 at 10:15 AM

Hi,

You don't have to tell which property to validate since it is already given on your configuration, which is under the <properties> node. You can't pass parameters dynamically to the validator but you can pass keys and values which can be configured on the configuration file. Moving on, I noticed that you are using a custom validator. Can you post the code here? The problem might be there.

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

 

Jun 22, 2011 at 3:39 PM

Hi Noel,

Thank you for your response.  Here is the code for the custom validator:

 [ConfigurationElementType(typeof(CustomValidatorData))]
    public class ItemTypeUniqueKeyCodeValidator : Validator<StorerTVItemType>
    {
        private string keyCode;
        private int siteId;

        public ItemTypeUniqueKeyCodeValidator(NameValueCollection collection)
            : base(null, null)
        {
        }

        public ItemTypeUniqueKeyCodeValidator()
            : base(null, null)
        {           
        }

        public ItemTypeUniqueKeyCodeValidator(int siteId, string keyCode)
            : base(null, null)
        {
            this.siteId = siteId;
            this.keyCode = keyCode;
        }

        protected override string DefaultMessageTemplate
        {
            get { throw new NotImplementedException(); }
        }

        protected override void DoValidate(StorerTVItemType objectToValidate, object currentTarget, string key, ValidationResults validationResults)
        {

            //Determine if key code already exists for this site

            ItemTypeService svc = new ItemTypeService();

            ItemTypeParameterBuilder builder = new ItemTypeParameterBuilder();
            builder.AppendEquals(ItemTypeColumn.SiteId, objectToValidate.SiteId.ToString());
            builder.AppendEquals(ItemTypeColumn.KeyCode, objectToValidate.KeyCode);

            TList<StorerTV.InventoryModule.Entities.StorerTVItemType> items = svc.Find(builder.GetParameters());

            if (key code exists)

          ValidationResult validationResult = new ValidationResult("Duplicate Item Type key code.", currentTarget, null, null, this);
                validationResults.AddResult(validationResult);
            }
        }
    }

(I initially had public properties for both KeyCode and SiteId, but removed them when I was not able to cast the ValidatorWrapper returned from the factory to a concrete validator.)  We want to use the factory because we want to take advantage of the VAB's configuration abilities (i.e. if we need to swap out validation routines, we can ask the factory to create another validator based on another rule set). 

This validator checks for duplicate key codes for a given site.  The end user enters key codes into a textbox on a web page and when he/she clicks the submit button, this validator fires.  That's why I asked if it was possible to use the factory to create this validator and pass it dynamic key codes (and siteIds).

If you need more informattion, please let me know.

Your help is greatly appreciated.

Joe

Jun 23, 2011 at 6:53 AM

You are getting that kind of error since in your config, you defined a validator for the property KeyCode, yet in your custom validator, the target of your validation is the whole object itself. As you can see on your DoValidate, the parameter "objectToValidate" is expecting a type of StorerTVItemType but it passed the type of "string" since you are particularly validating the KeyCode. To correct this, you should not specify a property to validate, just add your custom validator to the object directly so that the validation will take place on the object level. Then on your DoValidate, you can obtain the KeyCode property from objectToValidate. Can you further elaborate your validation scenario? Isn't the StorerTVItemType is the object that holds the user input? Also, where are you calling the validator?

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jun 23, 2011 at 2:15 PM
Edited Jun 23, 2011 at 2:43 PM

Hi Noel,

Thank you for your response.  The StorerTVItemType is the object that holds the user input.  (We are using NetTiers to generate our code and I am adding custom validation to the entities that NetTiers generates.)  Here is the custom Validate method for the StorerTVItemType entity.  I tried to use the factory on the line with the italicized comment.  There I had Validator<StorerTVItemType> itemTypeValidator = ValidationFactory.CreateValidator<StorerTVItemType>("ItemTypeRuleSet"); and below it, for the line that validates, I had itemTypeValidator.Validate(this, results);.

public override void Validate()
        {
            base.Validate();

            string methodName = null;
            Validator validator = null;
            ValidationResults results = new ValidationResults();

            if (base.EntityState == Entities.EntityState.Added)
            {
                methodName = "Add";
                validator = new ItemTypeUniqueKeyCodeValidator(); //I want to replace this call with the Factory
            }

           //irrelavent code deleted

            if (validator != null)
            {
                validator.Validate(this, results);

                if (!results.IsValid)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (ValidationResult valResult in results)
                    {
                        sb.Append(valResult.Message + Environment.NewLine);
                    }
                    throw new EntityNotValidException(this, methodName, sb.ToString());
                }
            }
        } 



Would you please explain more about using a custom validator to validate on the whole object itself?  I know that there exists a self-validation by decorating properties with the right attributes (although I am unfamiliar with the details that are associated with this).  Can this be done with custom validators without having to decorate the properties?

I also have a question regarding the declaration of the custom validator that I have written.  If I want to use the config file as it is, would I have to declare the custom validator as public class ItemTypeUniqueKeyCodeValidator : Validator<string>?  What if I need to validate two properties, one which is a string and the other which is an int?  Is this the scenario where I validate the object?

Finally, as I understand it, there are ways of combining (using And and Or combinations) validations.  How are these used with custom validators?  Can these be used to validate multiple properties in an object?

Your help is greatly appreciated.

Thank you,

Joe

Jun 24, 2011 at 4:40 AM

Modifying your config:

<validation>
    <type assemblyName="StorerTV.InventoryModule.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
      name="StorerTV.InventoryModule.Entities.StorerTVItemType">
      <ruleset name="ItemTypeRuleSet">

     <add type="StorerTV.Validators.ItemTypeUniqueKeyCodeValidator, StorerTV.Validators, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

        <!--<properties>
          <property name="KeyCode">
            <validator messageTemplate="" messageTemplateResourceName=""
              messageTemplateResourceType="" tag="" type="StorerTV.Validators.ItemTypeUniqueKeyCodeValidator, StorerTV.Validators, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
              name="Custom Validator" />
          </property>
        </properties>-->

 
      </ruleset>
    </type>
  </validation>

In the config, we removed the property node so that your validator will be tied to the whole object and not exclusively to the property you specified. When the DoValidate fires, the object  will be passed to the objectToValidate parameter. With that, you can now implement your own validation, for example, based on the properties of that object. This is also useful if you want to validate multiple properties in just one validation call. 

"I also have a question regarding the declaration of the custom validator that I have written.  If I want to use the config file as it is, would I have to declare the custom validator aspublic class ItemTypeUniqueKeyCodeValidator : Validator<string>?  What if I need to validate two properties, one which is a string and the other which is an int?  Is this the scenario where I validate the object?"

You can do that, but you also need to specify in your config that you are validating a type of string, for example the property. I hope it make all sense now, if you inherit from Validator<T> the T should also be the type of your target object you are validating. You can also specify a separate validator for each, but I find it convenient to validate directly the object which has those properties. 

Finally, as I understand it, there are ways of combining (using And and Or combinations) validations.  How are these used with custom validators?  Can these be used to validate multiple properties in an object?

Yes, it can be used with the different validators that validating your properties. The advantage of this is more flexibility since it is configurable.

 

Let me know if you have further questions :)

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com