Improved Validation for Universal Windows Apps

I wrote a couple weeks back on my attempt to re-write the ValidatableBase class I wrote for Universal Windows Apps. The original idea was great, but in practice it turned out to be a headache. Writing a method per property (in some cases more than one!) really bloated the code and made it difficult to read. So I set out to tackle this in a different way.

To demonstrate the improvements, I want to first revisit how the previous version worked. The following is a simple User model that would perform validation on a user name and password with the old ValidatableBase.

public class User : ValidatableBase
{
    private string email = string.Empty;

    private string password = string.Empty;

    public User()
    {
        this.RegisterProperty("Email", "Password");
    }

    public string Email
    {
        get 
        {
            return this.email;
        }
        set 
        { 
            this.email = value;
            this.OnPropertyChanged("Email");
        }
    }

    public string Password
    {
        get 
        { 
            return this.password; 
        }
        set 
        { 
            this.password = value;
            this.OnPropertyChanged("Password");
        }
    }

    public override void Validate()
    {
        this.ValidateProperty(this.ValidateEmailIsNotEmpty, "Invalid Email Address.", "Email");
        this.ValidateProperty(this.ValidateEmailIsFormatted, "Email Address is not in the correct format.", "Email");
        this.ValidateProperty(this.ValidatePasswordIsNotEmpty, "Password can not be empty.", "Password");
        this.ValidateProperty(this.ValidatePasswordIsToShort, "Password must be greater than 8 characters.", "Password");
        this.ValidateProperty(this.ValidateIfPasswordContainsSpaces, "Password must not contain spaces.", "Password");

        base.Validate();
    }

    private IValidationMessage ValidateEmailIsNotEmpty(string failureMessage)
    {
        if (string.IsNullOrEmpty(this.Email))
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }

    private IValidationMessage ValidateEmailIsFormatted(string failureMessage)
    {
        string[] addressParts = this.Email.Split('@');

        if (addressParts.Length < 2)
        {
            var msg = new ValidationErrorMessage(failureMessage);
            return msg;
        }

        string[] domainPiece = addressParts.LastOrDefault().Split('.');
        if (domainPiece.Length < 2)
        {
            var msg = new ValidationErrorMessage(failureMessage);
            return msg;
        }

        return null;
    }

    private IValidationMessage ValidatePasswordIsNotEmpty(string failureMessage)
    {
        if (string.IsNullOrEmpty(this.Password))
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }

    private IValidationMessage ValidatePasswordIsToShort(string failureMessage)
    {
        if (this.Password.Length < 8)
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }

    private IValidationMessage ValidateIfPasswordContainsSpaces(string failureMessage)
    {
        if (this.Password.Contains(' '))
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }
}

As you can see, I had to write a single method for each different type of validation I wanted to perform. In this case, as shown in the Validate() method, I have 5 different methods to validate 2 properties. Imaging a more complex model? This quickly turned in to a messy model.

The solution

I heavily modified the ValidatableBase class and its interface initially, but ultimately ended up being able to keep it mostly unchanged and just add on to it. The validation via method delegates certainly has a place, and I didn't want to loose that. The goal this time-around however was to make delegates the last choice instead of the first choice.

The class now supports attribute based validation, very much like Microsoft's DataAnnotation. Since Data Annotations are not supported in Universal Apps, I set out to build my own version, which actually ended up being a bit different with some nifty features.

Let's take the User class, and re-write it to use the new validation scheme.

public class User : ValidatableBase
{

    private string email = string.Empty;

    private string password = string.Empty;

    [ValidateValueIsNotNull(FailureMessage = "E-Mail can not be left blank.", ValidationMessageType = typeof(ErrorMessage))]
    [ValidateWithCustomHandler(DelegateName = "ValidateEmailFormat")]
    public string Email
    {
        get
        {
            return this.email;
        }

        set
        {
            this.email = value;
            this.OnPropertyChanged("Email");
        }
    }

    [ValidateStringIsGreaterThan(GreaterThanValue = 6, FailureMessage = "Password must be greater than 6 characters.", ValidationMessageType = typeof(ErrorMessage))]
    [ValidateStringIsLessThan(LessThanValue = 20, FailureMessage = "Password must be less than 20 characters.", ValidationMessageType = typeof(ErrorMessage))]
    public string Password
    {
        get
        {
            return this.password;
        }

        set
        {
            this.password = value;
            this.OnPropertyChanged("Password");
        }
    }

    [ValidationCustomHandlerDelegate(DelegateName = "ValidateEmailFormat")]
    private bool ValidateEmailIsFormatted(IMessage failureMessage)
    {
        string[] addressParts = this.Email.Split('@');

        if (addressParts.Length < 2)
        {
            return false;
        }

        string[] domainPiece = addressParts.LastOrDefault().Split('.');
        if (domainPiece.Length < 2)
        {
            return false;
        }

        return true;
    }
}

Now we are down to just a single method that performs validation. The Email property has two validation attributes, a ValidateValueIsNotNull and a ValidateWithCustomHandler attribute. The value is not null attribute is self explanatory, it just ensures the value isn't null and progresses. The ValidateWithCustomHandler allows you to specify a delegate name that you want th validator to use when performing validation. You'll notice that there no longer needs to be a method within the model called Validate() as this is part of the base class and handles invoking all of the validation attributes, and their custom handlers if they exist.

We use validation on the Password property as well, by ensuring it meets the minimum and maximum length requirements we define.

A really cool feature of this, is the ability to perform validation based on other property values. For instance, let's assume that validation for the Password can only fire when the Email property has a value set. If that is the case, then we just modify the Password attributes to specify that the Email property must be valid in order for our validation to fire.

    [ValidateStringIsGreaterThan(GreaterThanValue = 6, ValidateIfMemberValueIsValid = "Email",  FailureMessage = "Password must be greater than 6 characters.", ValidationMessageType = typeof(ErrorMessage))]
    [ValidateStringIsLessThan(LessThanValue = 20, ValidateIfMemberValueIsValid = "Email", FailureMessage = "Password must be less than 20 characters.", ValidationMessageType = typeof(ErrorMessage))]
    public string Password
    {
        get
        {
            return this.password;
        }

        set
        {
            this.password = value;
            this.OnPropertyChanged("Password");
        }
    }

As you can see here, by setting the ValidateIfMemberValueIsValid, the validation will only get fired if the Email property is not empty or null. What if we wanted to have validation fire only if the Email property was empty? We can do that be prepending an exclamation mark in from of the string representation of the Email property.

ValidateIfMemberValueIsValid = "!Email"

This works with boolean values by checking if it is true or false, floats, doubles, ints, longs, shorts and decimals by checking if they are zero or not along with empty strings and null objects.

Finally, the method delegate feature still exists, and can be used by external objects to enforce additional validation on the model. Let's use a view model as an example. Assume the view model has a PasswordConfirmation property, that must equal the users Password before user creation validation is considered acceptable. We can do the following in our view model, within a CreateUser method or an ICommand.Execute method.

    public void Execute(object parameter)
    {
        // Perform validation on the user's built in validation.
        this.AppUser.ValidateAll();

        // Piggy-back on top of the user default validation with an additional level of validation in our view model.
        // We ensure the password and password confirmation matches.
        this.AppUser.ValidateProperty(
            () => PasswordConfirmation.Equals(this.AppUser.Password),
            new ErrorMessage("Passwords do not match!"),
                "Password");

        // Check if there are any errors.
        if (this.AppUser.HasValidationMessages<ErrorMessage data-preserve-html-node="true">())
        {
            return;
        }

        // Do stuff.
        return;
    }

Here, we fire the user validation off, then we piggy-back on it by creating our own validation via an anonymous method, and assigning it to the "Password" property of the user. If validation fails, it will be added to the Users validation message collection. We then check if the user has any validation error messages. If they do, we abort the user creation.

The API still has a bit of tightening up to do before I can upload it, but it should be ready before the end of the week on GitHub. It's taken a bit of time due to ensuring that what I end up here can run properly. I managed to wire it up in to the latest build of the Mud Designer engine tonight which will really help with development.

Breaking Ground with Visual Studio Online

For my current project, I've chosen to host it on Visual Studio Online and make use of their source control, continuous integration via automated builds and Agile support.

Source Control

Visual Studio Online's source control (along with everything else) is handled through TFS. You are given the choice of using the TFS repository or a Git repository, that is managed by the TFS server. While I prefer Git, I chose the TFS repository since that is what I use at work. Since I use it on a daily basis, I am more comfortable and familiar with it. I want to spend my time learning better ways to code and building a quality product rather than spending time learning the ins and outs of Git via TFS Server.

The Visual Studio IDE has excellent source control support, so I was up and running really quick. I brought my self up to speed with the revised ALM Rangers Guide for branching strategies and got my branching system put together. Initially I'm starting with just a single branch, Main. Once the application gets to a stable point, I'll branch to a Dev branch and continue development there. I'll will ultimately end up with a Development and Release branch isolation strategy. Being a solo developer, I think this works well. It lets me stage chunks of code in Main, that will ultimately end up in Release, while continuing to develop new content in Dev until I am ready to ship Main.

Automated Builds

One of the things I'm really anxious to start doing, is automating my builds everytime I check in. Since Visual Studio online only provides you with 60 minutes of build time per month, I will probably only run continuous integration builds when I merge from my Dev branch in to Main and Release. When I am checking in code to Dev, I'm don't really need to have a build generated.

The nice part with this is that I can easily access a build of my application from anywhere. I just need to log in to Visual Studio Online, download the drop and run it. Since I don't like storing my source code on cloud services like OneDrive or Dropbox, this lets me access my source and drops from anywhere.

Agile

We use a variation of Agile at my work and I don't have any complaints with how Agile works. I used it somewhat with AllocateThis! when my buddy and I where working on some stuff together and found it helped provide a clear path for development. Typically, I just start writing code, then end up going back and re-writing code so that the new features I want work well with the old code. This time around, I'm going to plan properly.

I have crafted a series of user stories already and have a decent back log that is being built. An initial prototype of the app has already been wrote, so I've already got a decent idea of what is involved with creating a Universal Windows app. I will spend the next week or so finalizing the initial backlog, then start taking my prototype and building an actual product with it.

I'll post updates of my progress (without giving away to much detail!) as I develop the app. I kind of want to document a little bit the entire process, from start to finish, of creating a Universal Windows App Store app. Coming from WPF, it's been a bit of an adjustment. I had thought that they would be relatively the same (which they are); the differences however between the two frameworks are pretty significant and slowed my prototype development down. I imagine as I progress, my overall velocity should increase. At least until I start doing UI animation in Blend!

ValidatableBase for Universal WinRT apps on GitHub

I spent yesterday building a better way to do validations while writing a Universal WinRT app, and blogged about my end product. I decided I'd go ahead and make a GitHub project and upload the source, so it is freely available to anyone who needs Validation until prism and Universal WinRT apps can support it out of the box.

The following is from the projects ReadMe.md

ValidatableBase

Model Validation for Universal WinRT Apps. Since Universal WinRT apps targeting Windows 8.1 and Windows Phone 8.1 lack built in, easy to use data Validation, I wrote a quick model object that can be used to add validation to your apps.

An example model, providing validation making sure the name is not blank.

public class ModelFixture : ValidatableBase
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public override void Validate()
    {
        this.ValidateProperty((failureMessage) =>
            {
                if (string.IsNullOrEmpty(this.Name))
                {
                    return new ValidationErrorMessage(failureMessage);
                }
                return null;
            },
            failureMessage: "Name can not be blank!",
            propertyName: "Name");

        base.Validate();
    }
}

Advanced Example validating multiple business rules on a property, for multiple properties.

public class User : ValidatableBase
{
    /// < summary>
    /// The Email backing field.
    /// < /summary>
    private string email = string.Empty;

    /// < summary>
    /// The Password backing field.
    /// < /summary>
    private string password = string.Empty;

    /// < summary>
    /// Gets the Email.
    /// < /summary>
    /// < value>
    /// The Email.
    /// < /value>
    public string Email
    {
        get 
        {
            return this.email;
        }

        set 
        { 
            this.email = value;
            this.OnPropertyChanged("Email");
        }
    }
    /// < summary>
    /// Gets the Password.
    /// < /summary>
    /// < value>
    /// The Password.
    /// < /value>
    public string Password
    {
        get 
        { 
            return this.password; 
        }

        set 
        { 
            this.password = value;
            this.OnPropertyChanged("Password");
        }
    }

    /// < summary>
    /// Performs validation on the User.
    /// < /summary>
    public override void Validate()
    {
        this.ValidateProperty(this.ValidateEmailIsNotEmpty, "Invalid Email Address.", "Email");
        this.ValidateProperty(this.ValidateEmailIsFormatted, "Email Address is not in the correct format.", "Email");
        this.ValidateProperty(this.ValidatePasswordIsNotEmpty, "Password can not be empty.", "Password");
        this.ValidateProperty(this.ValidatePasswordIsToShort, "Password must be greater than 8 characters.", "Password");
        this.ValidateProperty(this.ValidateIfPasswordContainsSpaces, "Password must not contain spaces.", "Password");

        base.Validate();
    }

    /// < summary>
    /// Validates that the email is not empty.
    /// < /summary>
    /// < param name="failureMessage">The message to supply the error collection if validation fails.</param>
    /// < returns>Returns a ValidationErrorMessage if validation fails. Otherwise, null is returned.</returns>
    private IValidationMessage ValidateEmailIsNotEmpty(string failureMessage)
    {
        if (string.IsNullOrEmpty(this.Email))
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }

    private IValidationMessage ValidateEmailIsFormatted(string failureMessage)
    {
        string[] addressParts = this.Email.Split('@');

        if (addressParts.Length < 2)
        {
            var msg = new ValidationErrorMessage(failureMessage);
            return msg;
        }

        string[] domainPiece = addressParts.LastOrDefault().Split('.');
        if (domainPiece.Length < 2)
        {
            var msg = new ValidationErrorMessage(failureMessage);
            return msg;
        }

        return null;
    }

    /// < summary>
    /// Validates that the password is not empty.
    /// < /summary>
    /// < param name="failureMessage">The message to supply the error collection if validation fails.</param>
    /// < returns>Returns a ValidationErrorMessage if validation fails. Otherwise, null is returned.</returns>
    private IValidationMessage ValidatePasswordIsNotEmpty(string failureMessage)
    {
        if (string.IsNullOrEmpty(this.Password))
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }

    /// < summary>
    /// 
    /// < /summary>
    /// < param name="failureMessage">The message to supply the error collection if validation fails.</param>
    /// < returns>Returns a ValidationErrorMessage if validation fails. Otherwise, null is returned.</returns>
    private IValidationMessage ValidatePasswordIsToShort(string failureMessage)
    {
        if (this.Password.Length < 8)
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }

    /// < summary>
    /// Tests to see if the password contains any spaces.
    /// < /summary>
    /// < param name="failureMessage"></param>
    /// < returns></returns>
    private IValidationMessage ValidateIfPasswordContainsSpaces(string failureMessage)
    {
        if (this.Password.Contains(' '))
        {
            return new ValidationErrorMessage(failureMessage);
        }

        return null;
    }
}

View Model validation checks

This exposes validation methods to external objects as well. By inheriting from ValidatableBase, you can force validation checks on a model from within your view model.

    public bool CanExecute(object parameter)
    {
        // Perform validation on the user.
        this.AppUser.Validate();

        // Check if there are any errors.
        if (this.AppUser.HasValidationMessageType< ValidationErrorMessage>())
        {
            return false;
        }

        return true;
    }

Binding to the View

Binding to the view is really easy, using one of the two provided converters.

< Application.Resources>
    < converters:ValidationCollectionToSingleStringConverter x:Key="ValidationCollectionToSingleStringConverter" />
    < converters:IValidationMessageCollectionToStringCollectionConverter x:Key="CollectionConverter" />
< /Application.Resources>

Bind to a single error for a property.

< TextBlock x:Name="EmailValidationErrorTextBlock"
            Text="{Binding Path=AppUser.ValidationMessages[Email], 
                            Converter={StaticResource ValidationCollectionToSingleStringConverter}}"
            Foreground="Red" />

Bind to the entire collection of errors for a property

< ItemsControl ItemsSource="{Binding Path=AppUser.ValidationMessages[Password], 
                                    Converter={StaticResource CollectionConverter}}">
    < ItemsControl.ItemTemplate>
        < DataTemplate>
            < TextBlock Text="{Binding}"
                        Foreground="Red" />
        < /DataTemplate>
    < /ItemsControl.ItemTemplate>
< /ItemsControl>

Custom object validation in WinRT Universal Apps

I mentioned about a month ago that i was going to work on a task management app. Since the app is going to target both Windows Phone 8 and Windows 8, I thought it would make sense to make use of Microsoft's new Universal App set up. Unfortunately for me, this turned out to be a bigger challenge than I anticipated to get set up. I'll blog about the difficulties of setting the project up initially later, since it deals largly with Universal apps working with Prism, Unity and Mocking. Today, I'm going to go over one of the major things that the WinRT shared library is missing. Data Validation.

The big brother framework (WPF) contains an excellent set of tools for data validation. As does the Silverlight API. Microsoft has a lot of examples of working data validation in WinRT targeting Windows 8, but those all go out the door with a universal app supporting Windows Phone 8. So I built my own.

There are a number of ways you can approach this. To work through these examples, I have put together the following Account Creation View that the examples I show will be based on.

The XAML required to re-produce this is really straight forward. I centered a stack panel in a Grid row, put a couple TextBlocks and a couple TextBoxs along with a single Button. To keep things short on the blog, I will just provide the XAML required to display the account creation StackPanel.

< StackPanel Grid.Row="1"
            VerticalAlignment="Center"
            HorizontalAlignment="Center">

    < !-- E-Mail address input -->
    < TextBlock Text="Email"
                Style="{StaticResource TitleTextBlockStyle}" />
    < TextBox x:Name="EmailTextBox"
                Margin="0 5 0 0"
                MinWidth="200"
                Text="{Binding Path=Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    < TextBlock x:Name="EmailValidationErrorTextBlock"
                Foreground="Red" />

    < !-- Password input -->
    < TextBlock Text="Password"
                Margin="0 30 0 0"
                Style="{StaticResource TitleTextBlockStyle}" />
    < TextBox x:Name="PasswordTextBox"
                Margin="0 5 0 0"
                MinWidth="{Binding ElementName=EmailTextBox, Path=MinWidth}"
                Text="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    < TextBlock x:Name="PasswordValidationErrorTextBlock"
                Foreground="Red" />

    < !-- Login command button -->
    < Button Content="Create Account"
            Margin="0 10 0 0" />
</StackPanel>

Next, we need to create a model. The Model is simple and looks like this:

public class User : INotifyPropertyChanged
{
    private string email;
    private string password;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Email
    {
        get { return email; }
        set 
        { 
            email = value;
            this.OnPropertyChanged("Email");
        }
    }
    public string Password
    {
        get { return password; }
        set 
        { 
            password = value;
            this.OnPropertyChanged("Password");
        }
    }
    protected void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Now we are ready to go.

Code-Behind

The first option available for performing validation is doing it in the code-behind using an event handler. We can modify our Button XAML to include an event handler like this:

< Button Content="Login"
         Margin="0 10 0 0"
         Click="Button_Click" />

Now each time the button is called, it will fire the event. If you're a WPF developer, or have been doing Windows 8 development for awhile, you're probably yelling "This isn't WinForms!". I hear your shouts and agree, but for the sake of demonstrating a possible approach, let's follow this through to the end.

Next we need to write the validation in the code-behind. Since we are not maintaining view state, or using an ICommand implementation, we don't need to set up a View Model for this scenario. Binding to the Model is just fine. We just need to set it as our DataContext via the View's constructor.

public LoginPage()
{
    this.InitializeComponent();
    this.DataContext = new User();
}

Now we implement our event handler for the Create User button being clicked. This will handle all of our validation.

private void Button_Click(object sender, RoutedEventArgs e)
{
    User user = this.DataContext as User;
    if (user.Password.Length < 8)
    {
        this.PasswordValidationErrorTextBlock.Text = "Password must be a minimum of 8 characters";
    } 
    if (user.Password.Length > 16)
    {
        this.PasswordValidationErrorTextBlock.Text = "Password can not exceed 16 characters.";
    }
    if (string.IsNullOrEmpty(user.Email))
    {
        this.EmailValidationErrorTextBlock.Text = "Email can not be left blank.";
    }
}

This makes me cry a little inside each time I see it. There should never be any validation in your Code-Behind. Ever. Why you ask? Let's break it down.

  1. Testability. With this in the View's code-behind, you can't test any of your business rules.
  2. Reusability. We are writing the Create User View. What about Logging back in with an existing user? You'll want to re-use the same model wouldn't you? Ideally have part of the same validation, such as the blank email address being checked? You'll have to re-write the validation in each View with this approach.
  3. Violates the MVVM pattern. You should have all of the business logic outside of the View. The code-behind can be used to handle View related things, but never business logic.

View Model

Another option is to put the validation in the View Model, and let the UI know what the errors are by binding to error properties. In order to show this, we need to first remove the code-behind and create our View Model. It would look like this.

public class AccountCreationViewModel : INotifyPropertyChanged, ICommand
{
    private string emailEmptyError;
    private string passwordToShortError;
    private string passwordToLongError;

    private User appUser;

    public event PropertyChangedEventHandler PropertyChanged;

    public User AppUser
    {
        get { return appUser; }
        set 
        { 
            appUser = value;
            this.OnPropertyChanged("AppUser");
        }
    }
    public string EmailEmptyError
    {
        get { return emailEmptyError; }
        set 
        { 
            emailEmptyError = value;
            this.OnPropertyChanged("EmailEmptyError");
        }
    }
    public string PasswordToShortError
    {
        get { return passwordToShortError; }
        set 
        { 
            passwordToShortError = value;
            this.OnPropertyChanged("PasswordToShortError");
        }
    }
    public string PasswordToLongError
    {
        get { return passwordToLongError; }
        set 
        { 
            passwordToLongError = value;
            this.OnPropertyChanged("PasswordToLongError");
        }
    }
    protected void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public void Execute(object parameter)
    {
        if (AppUser.Password.Length < 8)
        {
            this.PasswordToShortError = "Password must be a minimum of 8 characters.";
            return;
        }

        if (AppUser.Password.Length > 16)
        {
            this.PasswordToLongError = "Password can not exceed 16 characters.";
            return;
        }

        if (string.IsNullOrEmpty(AppUser.Email))
        {
            this.EmailEmptyError = "Email can not be left blank.";
            return;
        }

        // Create the user
        // ......
    }
}

Already this is looking a bit hard to read. We are creating unnecessary properties in the View Model to keep track of validation errors. We would need to update our View to use the View Model as its data context along with updating the bindings on the TextBox's to bind to the ViewModel.AppUser object. We also need to bind our error TextBlocks to the error messages in the View Model

< Page.DataContext>
    < viewModels:AccountCreationViewModel />
< /Page.DataContext>

< TextBox x:Name="EmailTextBox"
            Margin="0 5 0 0"
            MinWidth="200"
            Text="{Binding Path=AppUser.Email, 
                           Mode=TwoWay, 
                           UpdateSourceTrigger=PropertyChanged}" />
< TextBox Margin="0 5 0 0"
          MinWidth="200"
          Text="{Binding Path=AppUser.Password, 
                           Mode=TwoWay, 
                           UpdateSourceTrigger=PropertyChanged}" />

< TextBlock Text="{Binding Path=PasswordToLongError}" 
            Foreground="Red"/>
< TextBlock Text="{Binding Path={PasswordToShortError}" 
            Foreground="Red"/>
< TextBlock Text="{Binding Path=EmailEmptyError}" 
            Foreground="Red"/>

Lastly, update our button so it fires the Excute method associated with the ICommand interface.

< Button Content="Create Account"
        Margin="0 10 0 0"
        Command="{Binding}" />

When the button is clicked, it will execute the command. The command will run through the business rules and update the error properties. Each time the error property is updated, the UI will reflect the errors.

This is still a bad approach to take. While this does make your code testable, your validation is still tightly coupled with your View (since each View should have their own View Model). It also continues to prevent your business logic from being reusable.

Custom validation in the Model

Now we get to the meat of this post. The validation should be placed in your Model object, so that your model is a complete object. It contains the properties it needs to do its job, it becomes self-validating and can be re-used through the app.

Moving our three error properties from the View Model in to the model is a bad idea however. The error properties are really used to assist the View in displaying errors and don't help the Model in any way. The model is already aware that it has validation issues. In WPF and WinRT for Windows 8 development, you would use INotifyDataErrorInfo. The View would be notified when a property validation error existed and could react accordingly. Unfortunately, we do not have that when you are building a Windows 8/Windows Phone Universal app. So I set out to create my own framework.

The first thing I did was created an interface that all models needing validation would be required to implement. I'll show the interface, then we will discuss it a bit further.

public interface IValidatable
{
    Dictionary< string, List< IValidationMessage>> ValidationMessages { get; }

    void AddValidationMessage(IValidationMessage message, string property = "");
    void RemoveValidationMessage(string message, string property = "");
    void RemoveValidationMessages(string property = "");
    bool HasValidationMessageType< T>(string property = "");
    IValidationMessage ValidateProperty(
        Func< string, 
        IValidationMessage> validationDelegate, 
        string failureMessage, 
        string propertyName = "");
}

So let's go over each method on by one.

ValidationMessages

This is a read-only property, that will contain all of our validation messages. The property has a Key typed to a string, which will be the Models property name. The value is a collection of IValidationMessage objects (We will discuss what the IValidationMessage is later). The idea being that for each property in the model, we can store more than 1 error.

AddValidationMessage(IValidationMessage message, string property = "");

This method is used to add a validation message to the ValidationMessages collection. The property will be assigned as the Key, with the message being added as the value.

RemoveValidationMesssage(IvalidationMessage message, string property = "");

Just like we can add a validation message, we will provide ourselves with the ability to remove it.

RemoveValidationMessages(string property = "");

We can use this method to completely clear out all validation messages in one shot for a single property.

HasValidationMessageType< T>(string property = "");

This method will return true if the object has validation messages matching < T> and false if it does not.

ValidateProperty(
    Func< string, 
    IValidationMessage> validationDelegate, 
    string failureMessage, 
    string propertyName = "");

This method can be called to actually perform validation on a property within the object and build the collection of errors. The arguments require a method delegate that returns an IValidationMessage object. This is how the validation becomes reusable. Each individual object can pass in a method delegate that performs the actual validation. The IValidatable implementation will take the results and determine if it must go in to the ValidationMessages collection or not.

IValidationMessage

It looks like a lot of the interface relies on a secondary interface called IValidationMessage doesn't it? This interface is really straight forward. It contains a single property called Message.

public interface IValidationMessage
{
    string Message { get; }
}

The idea with this, is that we can create objects that implement this interface, but containing different types of messages. For instance, in this post, we will create a ValidationErrorMessage and a ValidationWarningMessage. You could go on and create any kind of messaging you want and use it for binding to the View.

Implementing the IValidatable

Rather than having our User model implement this interface, we will implement it within a new Base class. We will call the class ValidatableBase.

public abstract class ValidatableBase : IValidatable, INotifyPropertyChanged
{
    private Dictionary< string, List< IValidationMessage>> validationMessages = 
        new Dictionary< string, List< IValidationMessage>>();
    public event PropertyChangedEventHandler PropertyChanged;
}

Our initial class contains the Dictionary that will hold our validation messages. Next, we implement the read-only property required by our interface.

public Dictionary< string, List< IValidationMessage>> ValidationMessages
{
    get
    {
        return this.validationMessages;
    }
    private set
    {
        this.validationMessages = value;
        this.OnPropertyChanged("ValidationMessages");
    }
}

The call to OnPropertyChanged will let the UI know that this collection has changed. This in most cases won't be used since the collection is read-only, but since it is going in to a base class, we want to provide support for that.

Next, we implement our HasValidationMessageType method.

public bool HasValidationMessageType< T>(string property = "")
{
    if (string.IsNullOrEmpty(property))
    {
        bool result = this.validationMessages.Values.Any(collection =>
            collection.Any(msg => msg is T));
        return result;
    }

    return this.validationMessages.ContainsKey(property);
}

In this method, we check if the collection contains a Key matching the property supplied. If it does, then we check it's values to see if any of them match the Type specified in < T>. This lets you do something like

HasValidationMessageType< ValidationErrorMessage>("Email");

to check if the model has a validation error on the email property.

The AddValidationMessage method is pretty easy as well.

public void AddValidationMessage(IValidationMessage message, string property = "")
{
    if (string.IsNullOrEmpty(property))
    {
        return;
    }

    // If the key does not exist, then we create one.
    if (!this.validationMessages.ContainsKey(property))
    {
        this.validationMessages[property] = new List< IValidationMessage>();
    }

    if (this.validationMessages[property].Any(msg => msg.Message.Equals(message.Message) || msg == message))
    {
        return;
    }

    this.validationMessages[property].Add(message);
}

In this method we create a new collection if the key doesn't exist yet, we then double check to ensure this validation message does not already exist in the collection. If not, we add it.

The two Removal methods are easy enough as well.

public void RemoveValidationMessage(string message, string property = "")
{
    if (string.IsNullOrEmpty(property))
    {
        return;
    }

    if (!this.validationMessages.ContainsKey(property))
    {
        return;
    }

    if (this.validationMessages[property].Any(msg => msg.Message.Equals(message)))
    {
        // Remove the error from the key's collection.
        this.validationMessages[property].Remove(
            this.validationMessages[property].FirstOrDefault(msg => msg.Message.Equals(message)));
    }
}

Here we just check if there is any message for the supplied Key and remove it. At the moment, this does not do any Type checking to see if there is more than one Type of object (Warning and Error) in the collection with the same message. The method just removes the first thing it finds and calls it good.

Removing the entire property from the collection is even easier.

public void RemoveValidationMessages(string property = "") 
  {
      if (string.IsNullOrEmpty(property))
      {
          return;
      }

      if (!this.validationMessages.ContainsKey(property))
      {
          return;
      }

      this.validationMessages[property].Clear();
    this.validationMessages.Remove(property);
}

We just check if a key exists that matches the property name and then clear out its messages contents and remove the key from the Dictionary.

Finally, we finish implementing the interface by building the ValidateProperty method. In this method, we just invoke the delegate we are provided, and accept a IValidationMessage object in return. If the return value is not null, then we add it to the ValidationMessages collection. If it is null, then we can assume that the validation passed and there are no issues. Since that is the case, we remove it from the validation collection.

public IValidationMessage ValidateProperty(
    Func< string, 
    IValidationMessage> validationDelegate, 
    string failureMessage, 
    string propertyName = "")
{
    IValidationMessage result = validationDelegate(failureMessage);
    if (result != null)
    {
        this.AddValidationMessage(result, propertyName);
    }
    else
    {
        this.RemoveValidationMessage(failureMessage, propertyName);
    }

    return result;
}

We have satisfied the requirements of the IValidatable interface, but there is one more method we need to add to the base class. This will let us group all of our property validations in to a single call.

public abstract void Validate();

We mark it as abstract, since the base class has nothing to validate, and we want to force any object that inherits from the base class to implement the method. If you don't want to do this, you can opt out of in your code. Not everyone needs to have this feature, thus the reason why it was left out of the interface.

Also, our base class implements the INotifyPropertyChanged method, so we will remove it from our model and put the implementation in to our base class.

public void OnPropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
    {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Revisiting our Model

Finally, we can revisit the model and add our fancy new validation. The first thing we have to do is change our class declaration. Initially, we implemented the INotifyPropertyChange interface, but since our base class implements this, we don't need to now. We just need to inherit from our base class.

public class User : ValidatableBase

Now that we are inheriting from our base class, we need to implement the required Validate() method. In order to keep with the Single-Responsibility-Principle, we will invoke other methods from within the Validate() method. Since we have to validate multiple properties, we should have each property validation be contained within it's own method. This makes it easier to test.

public override void Validate()
{
    this.ValidatePassword("Password");
    this.ValidateEmail("Email");

    // Passing in an empty string will cause the ValidatableBase indexer to be hit.
    // This will let the UI refresh it's error bindings.
    base.OnPropertyChanged(string.Empty);
}

Here we just invoke a ValidatePassword and ValidateEmail method. When we are done, we notify any observers that the entire object has changed by not specifying a property name in the call to OnPropertyChanged. This lets the observers (in this case, the View) know its bindings need to be refreshed.

public IValidationMessage ValidatePassword(string property)
{
    const string passwordToShortError = "Password must a minimum of 8 characters in length.";
    const string passwordToLongError = "Password must not exceed 16 characters in length.";
    if (this.Password.Length < 8)
    {
        var msg = new ValidationErrorMessage(passwordToShortError);
        return msg;
    }
    if (this.Password.Length > 16)
    {
        var msg = new ValidationErrorMessage(passwordToLongError);
        return msg;
    }

    return null;
}

public IValidationMessage ValidateEmail(string property)
{
    const string emailAddressEmptyError = "Email address can not be blank.";
    if (string.IsNullOrEmpty(this.Email))
    {
        var msg = new ValidationErrorMessage(emailAddressEmptyError);
        return msg;
    }
}

Now our model has proper validation. It is testable and reusable. Much, much better. Next, we need to revise our View Model. We will delete all of the error properties within it, along with the INotifyPropertyChanged implementation. We will only need the AppUser property and the ICommand implementation.

public class LoginPageViewModel : ICommand
{
    public LoginpageViewModel()
    {
        this.AppUser = new User();
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        this.AppUser.Validate();

        if (this.AppUser.HasValidationMessageType< ValidationErrorMessage>())
        {
            return;
        }

        // Create the user.
    }
}

We now have one more thing to do. We need to update our XAML. The Error TextBlocks will now bind to the ValidationMessages property within the model, using an index matching the property they are bound to.

<TextBlock data-preserve-html-node="true" data-preserve-html-node="true" Text="{Binding Path=AppUser.ValidationMessages[Password], 
                            Converter={StaticResource ValidationMessageConverter}}" 
            Foreground="Red"/>
<TextBlock data-preserve-html-node="true" data-preserve-html-node="true" x:Name="EmailValidationErrorTextBlock"
            Text="{Binding Path=AppUser.ValidationMessages[Email], 
                            Converter={StaticResource ValidationMessageConverter}}"
            Foreground="Red" />

You can see in this XAML that I am using a value converter when binding to the collection. That is because the binding is to an implementation of IValidationMessage. The UI does not know how to render this, so rather than overriding the ToString() method on each IValidationMessage implementation, I wrote a Value Converter.

public class ValidationMessageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (!(value is IEnumerable< IValidationMessage>))
        {
            return string.Empty;
        }

        var collection = value as IEnumerable< IValidationMessage>;
        if (!collection.Any())
        {
            return string.Empty;
        }

        return collection.FirstOrDefault().Message;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Now, when you run the app and enter an invalid Email or Password, the UI will automatically inform you of the validation errors when you press the Create Account button. If you ever need to add more Email validation (such as the proper email format) or more Password validation (such as not allowing specific characters) you can do so without needing to modify your View Model or your View.

If you need to add a whole new property to the Model, with validation, you can. You don't need to modify your View Model, you only need to add a TextBlock to the View to display the validation.

Before we end the post, I will show you two implementations of the IValidationMessage. They both do the same thing, but are Typed differently so that you can segregate your messages by Type. This gives more flexibility that using an Enum.

First is the Error validation message.

public class ValidationErrorMessage : IValidationMessage
{
    public ValidationErrorMessage() : this(string.Empty)
    { }

    public ValidationErrorMessage(string message)
    {
        this.Message = message;
    }

    public string Message { get; private set; }
}

Next is the Warning validation message.

public class ValidationWarningMessage : IValidationMessage
{
    public ValidationWarningMessage() : this(string.Empty)
    { }

    public ValidationWarningMessage(string message)
    {
        this.Message = message;
    }

    public string Message { get; private set; }
}

You can now potentially create a ItemsControl in your XAML, bind it to the ValidationMessages collection and build a DataTemplate for each IValidationMessage implementation, each with different styles applied. So you could have orange TextBlocks for Warnings and Red for Errors.

I hope you guys find this useful while building Windows 8/Windows Phone 8 Universal apps!