This is the second article in a planned series of articles concerning AOP with Unity Interception and Policy Injection:
- INotifyPropertyChanged AOP
- IDataErrorInfo AOP
- Policy Injection
- Performance and optimizations
- The final solution
I hope you will find this useful in your work; all feedback will be greatly appreciated.
The previous article discussed an implementation of the INotifyPropertyChanged aspect using Unity Interception AOP. Today we will see how a similar approach can be applied to another interface commonly used by WPF (as well as by ASP.NET MVC).
The IDataErrorInfo interface consists of two methods:
- an indexer accepting a property name (
columnName) parameter and - an
Errorproperty.
We will solely focus on the indexer, which returns error messages on a per-property basis.
The Validation Application Block allows developers to easily incorporate input validation via property attributes and/or application configuration, supporting a variety of provided validators, as well as custom ones.
IDataErrorInfo and VAB seem to be a perfect match, and have indeed been integrated. Adding Unity Interception will further simplify input validation, so that (presentation) models could be specified in the following manner:
[NotifyPropertyChanged, DataErrorInfo]
public class Contact : MarshalByRefObject, INotifyPropertyChanged, IDataErrorInfo
{
[StringLengthValidator(1, 20, MessageTemplate="First name length must be between {3} and {5}.")]
[ContainsCharactersValidator("0123456789", Negated = true, MessageTemplate = "First name cannot contain digits.")]
public string FirstName { get; set; }
[StringLengthValidator(1, 20, MessageTemplate = "Last name length must be between {3} and {5}.")]
[ContainsCharactersValidator("0123456789", Negated = true, MessageTemplate = "Last name cannot contain digits.")]
public string LastName { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get { return null; }
}
}
Note: The implementation presented below is limited to classes derived (possibly indirectly) from MarshalByRefObject.
