Building an Exception Factory

If you write a lot of code that takes dependencies in a method or constructor, you'll find that you write a lot of null checking like this:

public DefaultGame(ILoggingService loggingService, IWorldService worldService)
{
    if (loggingService == null)
    {
        throw new ArgumentNullException("loggingService", "Logging Service must not be null!");
    }
    else if (worldService == null)
    {
        throw new ArgumentNullException("worldService", "World Service must not be null!");
    }

    this.loggingService = loggingService;
    this.worldService = worldService;
}

Depending on the number of dependencies, this tends to bloat methods with more safety checks than actual code. I wanted to resolve this, and did so with a factory.

The factory needed to satisfy a few things.

  • Instance exceptions
  • Support stashing custom data in to the exceptions
  • Only throw if a given condition was met
  • Allow a callback if the conditions are not met (meaning no exception will be thrown)

Turns out this was pretty easy to implement. The end product, in its simplest form looks like this:

public DefaultGame(ILoggingService loggingService, IWorldService worldService)
{
    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(loggingService == null);
    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(worldService == null);

    this.loggingService = loggingService;
    this.worldService = worldService;
}

You can also invoke a callback, and provide a custom message.

public DefaultGame(ILoggingService loggingService, IWorldService worldService)
{
    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(loggingService == null, "Logging Service must not be null!")
        .ElseDo(() => this.loggingService = loggingService);

    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(worldService == null, "World Service must not be null!")
        .ElseDo(() => this.worldService = worldService);
}

If you need to do something more complex with your conditional check, you use a Func< bool>

ExceptionFactory
    .ThrowExceptionIf< Exception>(
        () =>
        {
            this.Worlds = worldService.GetAllWorlds();
            return this.Worlds.Any();
        },
        "An empty world can not be used!"));

It also supports providing a custom exception factory method for use. Since some exceptions have additional parameters in the constructor, this can be really useful.

ExceptionFactory
    .ThrowExceptionIf< ArgumentNullException>(
        worldService == null,
        () => new ArgumentNullException("worldService", "World Service must not be null!"));

We can also pass custom data in to the exception if we want.

ExceptionFactory
    .ThrowExceptionIf< ArgumentNullException>(
        worldService == null,
        () => new ArgumentNullException("worldService", "World Service must not be null!"),
        new KeyValuePair< string, string>("Member", "DefaultGame"),
        new KeyValuePair< string, string>("MemberType", "Constructor"));

So how does the insides work? Let's take a look

The Factory

There are a total of four factory methods.

  • ThrowExceptionIf< TException>(Func< bool> predicate, string message = null, params KeyValuePair< string, string>[] data);
  • ThrowExceptionIf< TException>(Func< bool> predicate, Func< TException> exception, params KeyValuePair< string, string>[] data)
  • ThrowExceptionIf< TException>(bool condition, string message = null, params KeyValuePair< string, string>[] data)
  • ThrowExceptionIf< TException>(bool condition, Func< TException> exception, params KeyValuePair< string, string>[] data)

and one last method for adding data to the exception

AddExceptionData(Exception exception, params KeyValuePair< string, string>[] data)

Since we can build this in an overloaded fashion, we will just build the most complex method out, then let the rest of them piggy back on top of it.

public static ExceptionFactoryResult ThrowExceptionIf< TException>(bool condition, Func< TException> exception, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    if (condition)
    {
        return new ExceptionFactoryResult();
    }

    TException exceptionToThrow = exception();
    AddExceptionData(exceptionToThrow, data);

    throw exceptionToThrow;
}

This method is really straight forward, it requires a bool value to indicate if this exception must be instanced and thrown or not. If the condition is false, then we go ahead and invoke the Func< TException> delegate. This returns the exception that we are to throw.

Next we take the optional exception data parameter and pass it to an AddExceptionData method. That method will iterate over the param data and add it to the exception. We then finally throw the exception. Really straight forward.

The AddExceptionData method looks like this:

public static void AddExceptionData(Exception exception, params KeyValuePair< string, string>[] data)
{
    foreach (var exceptionData in data)
    {
        exception.Data.Add(exceptionData.Key, exceptionData.Value);
    }
}

Now we can build out our overloads. The second most complex one is really easy to write. We just pass a delegate in that instances a new exception using the Activator class.

public static ExceptionFactoryResult ThrowExceptionIf< TException>(bool condition, string message = null, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    return ThrowExceptionIf< TException>(
        condition,
        () => (TException)Activator.CreateInstance(typeof(TException), message),
        data);
}

Next, we will provide support for delegate predicates.

public static ExceptionFactoryResult ThrowExceptionIf< TException>(Func< bool> predicate, Func< TException> exception, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    return ThrowExceptionIf< TException>(predicate(), exception, character, data);
}

public static ExceptionFactoryResult ThrowExceptionIf< TException>(Func< bool> predicate, string message = null, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    return ThrowExceptionIf< TException>(predicate(), message, character, data);
}

The last thing we need to do is support the method callbacks. This is done using the ExceptionFactoryResult class that all of our factory methods return. This class has nothing more than a simple method that takes an Action and invokes it.

public class ExceptionFactoryResult
{
    public void ElseDo(Action callback)
    {
        callback();
    }
}

That's all there is to it!

ValidatableBase 2.0

A couple of weeks ago I released verison 2.0 of ValidatableBase on GitHub. The newest build provides Data Annotation styled attribute validation for Universal Windows applications, iOS, Android and any other platform that .NET Portable Class Libraries can run on.

Release features

  • New Data Annotation styled attribute validation system has been added. The attributes implement IValidationRule and provide a simple means of writing custom validation rules if needed.
  • Registration of properties is no longer needed.
  • The library is now in a Portable Class Library, usable across all platforms that PCL's can run on.
    • As a side-effect of this, the validation messages collection is no longer directly exposed. The underlying implementation is Dictionary< string, IEnumerable< IValidationMessage>> which requires conversion if you need to bind to the validation results. The example app includes an extension method that can be used to perform the conversion, for view models that want to expose validation to the view.
  • ValidatableBase now has a ValidationChanged event that you can subscribe to. Any time validation is changed, either by adding/removing messages or running validation, your view models can be notified.

Validation Rule examples

ValidatableBase supports a very flexible attribute based validation system that can be used on any of your models, regardless of platform.

To demonstrate, let's create a very basic model with zero validation.

namespace SampleUniversalApp.Models
{
    using System.ComponentModel;
    using System.Linq;
    using System.Reflection;
    using Sullinger.ValidatableBase.Models;
    using Sullinger.ValidatableBase.Models.ValidationRules;

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

        private string password = string.Empty;

        public event PropertyChangedEventHandler PropertyChanged;

        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");
            }
        }

        protected virtual void OnPropertyChanged(string propertyName = "")
        {
            var handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

This model is really straight-forward and shouldn't need any explaining. It implements INotifyPropertyChanged and has two properties.

Validation

Now that we have a model, we want to validate it. We will perform validation on both the Email and the Password properties. We want to make sure neither of them are blank.

The first thing we have to do is inherit from a concrete Type implementing IValidatable. The ValidatableBase API ships with a base class called ValidatableBase (surprise, surprise) that you can use.

Update your class definition to look like the following:

public class User : ValidatableBase, INotifyPropertyChanged

Since the ValidatableBase API is cross-platform and lives within a Portable Class Library, the ValidatableBase class does not implement INotifyPropertyChanged. If you are targeting a platform that supports this (such as WPF) then you can build a secondary base-class on top of ValidatableBase, or build your own implementation of IValidatable.

The ValidatableBase API performs validation mostly through attributes. To make sure neither property is left blank, we will decorate each property with a ValidateObjectHasValue attribute.

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

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

    [ValidateObjectHasValue(
        FailureMessage = "Password can not be left blank.",
        ValidationMessageType = typeof(ValidationErrorMessage))]
    public string Password
    {
        get
        {
            return this.password;
        }

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

Performing the validation

The next step is to obviously perform the validation. To do that, we will create a view model that implements ICommand, exposing an Execute method.

public class MainPageViewModel : ICommand, INotifyPropertyChanged
{
    public MainPageViewModel()
    {
        this.AppUser = new User();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public event EventHandler CanExecuteChanged;
    public User AppUser { get; private set; }

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

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

        // Do stuff.
        return;
    }

We have now validated our model. You can check if the model has any validation messages (indicating failure) by using the HasValidationMessages< IValidationMessage>() method.

if (this.AppUser.HasValidationMessages< ValidationErrorMessage>())
{
    // Failed, so abort.
    return;
}

Adding additional validation rules.

Since the models validation is performed by the attributes, we can come back at a later date and add or replace validation on the properties without having to re-write a large amount of logic code. To demonstrate, we will replace the Password properties validation. Instead of checking if the property is empty, we will check if the password entered meets a required password range of 6 to 20 characters.

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

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

Now when we run the this.AppUser.ValidateAll() method, the property will ensure it has a password between the range of 6 characters and 20. If not, a ValidationErrorMessage is created.

Mud Designer's first real sprint

Now that I have Mud Designer moved over to Visual Studio Online (VSO) I can start really making use of the Agile platform that VSO is built on top of. Going forward, the project will adopt the Agile methodology, with developing taking place during sprints.

The first sprint started today with three User Stories being brought in to the sprint.

  • Text File Data Storage Service
  • Character Security Permissions
  • Command Security

Text File Data Storage Service

Once this is completed, I will have the first of many data storage services created. The intent is to create a simple data store to use while I build the rest of the engine. I have other Stories for creating SQL and Cloud based services, but those are more complex. While the engine is being developed, I want to just use a simple local data store.

Character Security Permissions

This story contains the meat of the engines security framework. When completed, Permissions can be created and assigned to Roles. There will be a framework constructed for objects that need specific security permissions, to register for them.

Command Security

Pigging backing on top of the Character Security Permissions story, this will allow Commands to register for permissions they require. The engine will ensure that users have the required permissions within their roles before letting them execute the command.

Wrapping up

Since I am the only developer, each sprint is scheduled for 4 weeks, so it will be a bit before this sprint is completed. If the user stories are finished early, I will pull more stories in and continue working until the end of the sprint.

As each story is completed, I plan on writing a post on what work was done and what the features are. I would also like to do a code analysis and report the quality of the code for each story.

Mud Designer Migrated to Git

I have been really wanting to use the Visual Studio Online (VSO) service for a while now with Mud Designer. I have been holding back primarily because Mud Designer is open source, while VSO is meant for closed-source team projects. TFS doesn't come with an easy way of maintaining two repositories of the same code-base, while maintaining the version history of the source.

The solution to this was Git, but the Codeplex project was hosted on a TFS instance. I then discovered - (thanks to Richard Banks for answering my Stackoverflow post) - that the Codeplex team could convert my project to a Git repository. I promptly fired them an e-mail and had my project converted.

Now that Mud Designer was sitting in a Git project, I cloned it to VSO. Now any time I push changes to VSO, I can simultaneously push changes to Codeplex. This lets me make use of VSO's Agile work items, such as User Stories, sprints and bug tracking, while keeping the source freely available to the public. Win win!