Print

Using IDataErrorInfo with Validation Application Block

The IDataErrorInfo interface is a core part of the .NET framework and both WPF and ASP.NET MVC use this interface for validation purposes. In this article I will show how to build an abstract base class that implements IDataErrorInfo in a way that Validation Application Block is used under the covers.

Using the IDataErrorInfo interface on domain or ViewModel objects is one of the ways to leaverage validation in UI technologies such as WPF and ASP.NET MVC. Having to implement that interface (with its properties) on each and every ViewModel or domain object however, is quite cumbersome and is certainly not DRY. It is much more convenient to use a base class that implements everything you need. This way, instead of having to implement the complete IDataErrorInfo interface, we can simply inherit from this base class:

public partial class Customer : DataErrorInfo
{
}

Below is the code for the DataErrorInfo class. If you look closely you will see a couple of interesting things. First of all, the IDataErrorInfo interface members are implemented explicitly to prevent them from showing up using IntelliSense, because they have no other purpose than for validation by a UI technology. Next, the code uses VAB’s PropertyValidationFactory to ensure only the requested property is validated. Not only is this more efficient than validating the complete entity, it also prevents us from having to figure out which errors are caused by that particular property.

public abstract class DataErrorInfo : IDataErrorInfo
{
string IDataErrorInfo.Error
{
get { return DataErrorInfoHelper.GetErrorInfo(this); }
}

string IDataErrorInfo.this[string columnName]
{
get { return DataErrorInfoHelper.GetErrorInfo(this, columnName); }
}
}

public static class DataErrorInfoHelper
{
public static string GetErrorInfo(object entity)
{
var type = entity.GetType();
var validator =
ValidationFactory.CreateValidator(type);
var results = validator.Validate(entity);
return String.Join(" ",
results.Select(r => r.Message).ToArray());
}

public static string GetErrorInfo(object entity,
string propertyName)
{
PropertyInfo property =
entity.GetType().GetProperty(propertyName);

return GetErrorInfo(entity, property);
}

public static string GetErrorInfo(object entity,
PropertyInfo property)
{
var validator = GetPropertyValidator(entity,
property);

if (validator != null)
{
var results = validator.Validate(entity);

return String.Join(" ",
results.Select(r => r.Message).ToArray());
}

return string.Empty;
}

private static Validator GetPropertyValidator(
object entity, PropertyInfo property)
{
string ruleset = string.Empty;
var source = ValidationSpecificationSource.All;
var builder = new ReflectionMemberValueAccessBuilder();

return PropertyValidationFactory.GetPropertyValidator(
entity.GetType(), property, ruleset, source, builder);
}
}

When you are in the unlucky position of using Entity Framework 3.5 (my condolences btw), you are stuck to inheriting your entities from EntityObject or ComplexObject. In that case, you need to define the partial class as follows:

public partial class Customer : IDataErrorInfo
{
string IDataErrorInfo.Error
{
get { return DataErrorInfoHelper.GetErrorInfo(this); }
}

string IDataErrorInfo.this[string columnName]
{
get { return DataErrorInfoHelper.GetErrorInfo(this, columnName); }
}
}

In other words, you can't inherit from a base type, but must implement IDataErrorInfo directly and implement the interface members in each type.

Happy validating.

- .NET General, C#, Enterprise Library, Validation Application Block - four comments / No trackbacks - §

The code samples on my weblog are colorized using javascript, but you disabled javascript (for my website) on your browser. If you're interested in viewing the posted code snippets in color, please enable javascript.

four comments:

This is very great!!
Thank you!
Sven - 21 04 11 - 09:58

Very nice
Eric - 06 06 11 - 05:12

thanks.

you're missing the "this" keyword in your extension method..should be

private static Validator GetPropertyValidator(this object entity, PropertyInfo property)
Justin - 13 03 12 - 21:35

Thanks Justin,

I fixed the bug.
Steven (URL) - 13 03 12 - 21:41