Validate only specific property

Topics: Validation Application Block
Mar 17, 2010 at 3:57 PM

Hi there,

Is there a way to validate only single property on an object based on the rule attributes applied to it, rather than validating the entire object?

I want to perform validation inside IDataErrorInfo.this[string propertyName], which gets called multiple times on each property, and it seems calling Validation.Validate<T>(T target) would be inefficient.

Thanks,

-Dash. 

Mar 18, 2010 at 10:03 AM

Hi,

Here is one way to  validate a single property : http://entlib.codeplex.com/Thread/View.aspx?ThreadId=42731

Valiant Dudan
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com

Mar 18, 2010 at 11:31 AM

Have to actually measured the performance? I'd normally wouldn't expect any noticeable loss of performance. You can try it out with this code:

string IDataErrorInfo.this[string propertyName]
{
    get
    {
        var validator = 
            ValidationFactory.CreateValidator(this.GetType());

        var errorMessagesForProperty =
            from result in validator.Validate(this)
            where result.Key == propertyName
            select result.Message;

        return String.Join(" ", errorMessagesForProperty.ToArray());
    }
}

Cheers

Mar 23, 2010 at 10:31 AM
Edited Mar 23, 2010 at 2:20 PM

There is a way to only get the validators for a particular property. The Validation Application Block contains a PropertyValidationFactory that allows creating validators for properties. However, this type is internal, so you can’t access it directly (without reflection of course). However, it can be accessed indirectly by using the ValidationIntegrationHelper. In that case you will have to create a custom implementation of the IValidationIntegrationProxy interface and supply it as constructor argument to the ValidationIntegrationHelper. After that, you can call the CreateValidator() method on the ValidationIntegrationHelper and you’re done.

This is what your code may look like:

var instanceToValidate = new MyType();

var proxy = new PropertyValidationIntegrationProxy(
    instanceToValidate, "NameOfProperty");

var validator =
    new ValidationIntegrationHelper(proxy).GetValidator();

var results = validator.Validate(instanceToValidate);

The only thing left to do is to create the PropertyValidationIntegrationProxy, that should be a piece of cake ;-). But just to help you out, here’s an implementation:

 

public class PropertyValidationIntegrationProxy 
: IValidationIntegrationProxy
{
private readonly object instanceToValidate;
private string ruleset;
private ValidationSpecificationSource specificationSource =
ValidationSpecificationSource.Both;

public PropertyValidationIntegrationProxy(object instanceToValidate,
string validatedPropertyName)
{
if (instanceToValidate == null)
{
throw new ArgumentNullException("instanceToValidate");
}

this.instanceToValidate = instanceToValidate;
this.ValidatedPropertyName = validatedPropertyName;
}

public MemberValueAccessBuilder GetMemberValueAccessBuilder()
{
return new PropertyMappedValidatorValueAccessBuilder();
}

public object GetRawValue()
{
var flags = BindingFlags.Public | BindingFlags.Instance;
var validatedProperty = this.ValidatedType.GetProperty(
this.ValidatedPropertyName, flags);

return validatedProperty.GetValue(this.instanceToValidate, null);
}

public void PerformCustomValueConversion(ValueConvertEventArgs e)
{
}

public bool ProvidesCustomValueConversion { get { return false; } }

public string Ruleset
{
get { return ruleset ?? String.Empty; }
set { this.ruleset = value; }
}

public ValidationSpecificationSource SpecificationSource
{
get { return this.specificationSource; }
set { this.specificationSource = value; }
}

public string ValidatedPropertyName { get; private set; }

public Type ValidatedType
{
get { return this.instanceToValidate.GetType(); }
}

private class PropertyMappedValidatorValueAccessBuilder
: MemberValueAccessBuilder
{
protected override ValueAccess DoGetFieldValueAccess(
FieldInfo fieldInfo)
{
throw new NotSupportedException();
}

protected override ValueAccess DoGetMethodValueAccess(
MethodInfo methodInfo)
{
throw new NotSupportedException();
}

protected override ValueAccess DoGetPropertyValueAccess(
PropertyInfo propertyInfo)
{
return new PropertyMappedValidatorValueAccess(
propertyInfo.Name);
}

private class PropertyMappedValidatorValueAccess : ValueAccess
{
private readonly string propertyName;

public PropertyMappedValidatorValueAccess(string propertyName)
{
this.propertyName = propertyName;
}

public override bool GetValue(object source, out object value,
out string valueAccessFailureMessage)
{
var proxy = new PropertyValidationIntegrationProxy(
source, this.propertyName);

valueAccessFailureMessage = null;
value = proxy.GetRawValue();

return true;
}

public override string Key
{
get { return this.propertyName; }
}
}
}
}

I hope this helps.