Although I’ve worked with WWF (Windows Workflow Foundation) during all 2009, I haven’t posted anything about the technology yet, so I thought it was maybe the time to do it. I’ll start with one of the bases of the implementation of custom ActivityValidator classes. Despite being simple, that is an error that strikes new workflow developers quite often.

When creating a custom ActivityValidator, you might receive a compilation error from the newly created validator, even when the custom Activity it is targeted against is not in use yet.

But how come? Let’s take a look at the example below:

[ActivityValidator(typeof(MyCustomValidator))]
public partial class MyCustomActivity : Activity
{
    public static DependencyProperty PriceProperty = DependencyProperty.Register("Price", typeof(float), typeof(MyCustomActivity));

    [DescriptionAttribute("Price")]
    [CategoryAttribute("Price Category")]
    [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
    public float Price
    {
        get
        {
            return ((float)(base.GetValue(MyCustomActivity.PriceProperty)));
        }
        set
        {
            base.SetValue(MyCustomActivity.PriceProperty, value);
        }
    }

	public MyCustomActivity()
	{
		InitializeComponent();
	}
}

public class MyCustomValidator : ActivityValidator
{
    public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
    {
        MyCustomActivity myCustomActivity = obj as MyCustomActivity;
        ValidationErrorCollection errors = base.Validate(manager, obj);

        if (myCustomActivity == null)
        {
            throw new ArgumentException("MyCustomValidator can only be used to validate MyCustomActivity instances.", "obj");
        }

        if (myCustomActivity.Price <= 0)
        {
            errors.Add(new ValidationError("'Price' must be greater than zero.", 1));
        }

        return errors;
    }
}

In the example above, when you build the project you will receive an error such as

Error 1 Activity 'MyCustomActivity' validation failed: 'Price' must be greater than zero.

Well, that is not nice. You are not even using MyCustomActivity yet!

The reason for that is simple: validators are run during runtime, but also during build time! To avoid the error, we simply check if the custom activity is in use. How? Take a peak:

public class MyCustomValidator : ActivityValidator
{
    public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
    {
        MyCustomActivity myCustomActivity = obj as MyCustomActivity;
        ValidationErrorCollection errors = base.Validate(manager, obj);

        if (myCustomActivity == null)
        {
            throw new ArgumentException("MyCustomValidator can only be used to validate MyCustomActivity instances.", "obj");
        }

        if (myCustomActivity.Parent != null)
        {
            if (myCustomActivity.Price <= 0)
            {
                errors.Add(new ValidationError("'Price' must be greater than zero.", 1));
            }
        }

        return errors;
    }
}

As you can see, all we did was checking if the activity parent is not null (line 13).

Try to build now, no error will be triggered. Then drop MyCustomActivity to a workflow, don't fill in Price and build again. The error is now there, correctly returned!

Well, that was it... No black magic but surely resourceful! I hope it helps!