Activity Validation Logic Overview

The validator component of an activity contains all design-time and run-time validation logic. This ensures that the activity's properties that are defined in the activity's metadata are appropriately configured.

Windows Workflow Foundation provides extensive default validation capabilities, so in many cases you do not have to write a custom validator for your activity. If you do write a custom validator class, your custom class must inherit from ActivityValidator or one of its derived classes.

Note

Activity instance properties are not validated when you set the ValidationOptionAttribute to ValidationOption.Required. If you want instance properties in your custom activities to be validated, you must create your own custom validator to do this.

Validation occurs when an activity is added to the design surface of a workflow, during the compilation of a workflow, and whenever the Validate method of a validator component for an activity is called with the corresponding activity metadata object as a parameter. This enables a workflow authoring tool to use a "correct-by-construction" paradigm. Validation also occurs at runtime when a workflow is created unless ValidateOnCreate is set to false.

Additionally, validation occurs on a workflow instance at runtime when a workflow change is performed. This validation might differ from the validation performed at compile time. This functionality ensures the safety of a run-time operation, such as the addition or replacement of an activity in the activity tree of a running workflow instance. To provide additional validation when an activity is added or removed during a workflow change, override ValidateActivityChange in your custom validator class.

The following example shows how to create a custom activity validator by deriving from the ActivityValidator class and overriding the Validate method to add custom validation code. In this example the activity that is validated is a custom ConsoleWriteLineActivity activity that has a single dependency property named Msg of type String.

class ConsoleWriteLineActivityValidator : ActivityValidator
{
    public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
    {
        // Invoke the base class method implementation to
        // perform default validation.
        ValidationErrorCollection errors = base.Validate(manager, obj);

        // Make sure there is an activity instance.
        ConsoleWriteLineActivity crw = obj as ConsoleWriteLineActivity;
        if (crw == null)
        {
            throw new InvalidOperationException();
        }

        // If the activity has no parent then this validation
        // is occurring during the compilation of the activity
        // and not during the hosting or creation of an
        // activity instance.
        if (crw.Parent == null)
        {
            // Can skip the rest of the validation because
            // it deals with the hosting and the creation
            // of the activity.
            return errors;
        }

        // Msg is required. Add a validation error if there is no
        // Msg specified or Msg is not bound to another property.
        if (string.IsNullOrEmpty(crw.Msg) &&
            crw.GetBinding(ConsoleWriteLineActivity.MsgProperty) == null)
        {
            errors.Add(new ValidationError("Msg is required", 100, false, "Msg"));
        }

        return errors;
    }
}

To use your custom validator with your activity, you must apply the ActivityValidatorAttribute to your activity as shown in the following example.

[ActivityValidator(typeof(ConsoleWriteLineActivityValidator))]
public partial class ConsoleWriteLineActivity : System.Workflow.ComponentModel.Activity
{
    public ConsoleWriteLineActivity()
    {
        InitializeComponent();
    }

    public static DependencyProperty MsgProperty = System.Workflow.ComponentModel.DependencyProperty.Register("Msg", typeof(string), typeof(ConsoleWriteLineActivity));

    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public string Msg
    {
        get
        {
            return ((string)(base.GetValue(ConsoleWriteLineActivity.MsgProperty)));
        }
        set
        {
            base.SetValue(ConsoleWriteLineActivity.MsgProperty, value);
        }
    }

    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {
        Console.WriteLine(Msg);
        return ActivityExecutionStatus.Closed;
    }
}

If the ConsoleWriteLineActivity activity is hosted in a workflow and the Msg property is not populated, a validation error occurs. If the project is compiled, the following error appears in the Output Window.

error WF100: Activity 'consoleWriteLineActivity1' validation failed: Msg is required

The message and the error number are specified when the ValidationError is created.

errors.Add(new ValidationError("Msg is required", 100, false, "Msg"));

If Msg is not a required property, then you can pass true as the value to the third parameter of the ValidationError constructor, which makes the validation result a warning instead of an error.

See Also

Reference

Validator

Concepts

Creating Custom Activities

Other Resources

Developing Windows Workflow Foundation Activities