.NET Exceptions – System.Activities.ValidationException

Moving along through our in-depth .NET Exception Handling series, today we’ll dig deeper into the System.Activities.ValidationException. The System.Activities.ValidationException is meant to be thrown when a Windows Workflow Foundation element, such as an Activity or Workflow, is in an invalid state.

In this article we’ll briefly examine what the Windows Workflow Foundation is, and how the System.Activities.ValidationException can be used in such applications. We’ll also look at where the System.Activities.ValidationException fits in the larger .NET Exception hierarchy, along with a few functional C# code samples that illustrate how a Windows Workflow Foundation application might be created, so let’s get started!

The Technical Rundown

When Should You Use It?

Before we get into the ValidationException itself let’s take a moment to explore the Windows Workflow Foundation (WWF) on which it relies. The official documentation features a great deal of useful information and tutorials, but the basic purpose of the WWF is to make it relatively easy to create workflows that closely resemble or mirror real world processes. Typically this is accomplished by creating sets of activities that indicate a particular action. A workflow typically consists if a series of activities, all linked together through various logical means, to form the whole of the process.

The WWF is designed to make it easy to create and manage workflows within a visual editor. This allows members of the sales team, for example, to create and manipulate activities and adjust basic logic of the workflow process.

That said, it’s rather difficult to illustrate and explain the creation and visual manipulation of workflows within Visual Studio using only words and limited screen captures, so we’ll stick to creating coded examples of workflows, activities, and sequences. Both the visual and programmatic form of workflows are completely valid, but it will be much easier to follow along if everything is written in code.

With that said, let’s start with the full code sample below, after which we’ll examine each section in more detail to see how it all works:

Since our goal is to show how an exception like a System.Activities.ValidationException can be thrown, we have two different avenues by which we’ve programmatically created a workflow. We start with the CreateWorkflowSequence() method, which starts by creating a new Sequence activity and adds three Activities to it, which will be executed in order. The second Activity is a Throw object, which allows us to throw an exception, so here we’re throwing a System.Activities.ValidationException as a new InArgument<Exception> object:

With the Sequence created, we then need a way to handle the exception, so we’ve created a new WorkflowApplication instance and passed our sequence object as the primary Activity that will be executed. Within the WorkflowApplication declaration we specify a delegate to handle unhandled exceptions. In this case, we’re just outputting the Exception using the Logging.Log(Exception) method, then terminating the workflow that caused the issue.

Keen observers may also have noticed the Utility.Activities.LoggerActivity object we were using as our first and last Activity. This is a custom class that inherits from CodeActivity, which can be used to create custom activities with virtually any code and logic we want:

Nothing too fancy going on in this class, but by inheriting from CodeActivity we can override the Execute(CodeActivityContext) method, which is fired when the Activity executes. With a combination of InArgument<T> properties, we’re able to use various Logging.Log() method overloads to output the passed property values of this activity. TLDR: LoggerActivity allows us to spruce up our output, as compared to just using a new WriteLine object as an Activity.

With all that setup, now we can call the CreateWorkflowSequence() method:

The expectation is that our custom Sequence activity workflow will execute by starting with the first LoggerActivity output message, then it will throw of a new System.Activities.ValidationException, which should be caught by the OnUnhandledException delegate that was specified in the WorkflowApplication declaration. This should then output our error and terminate the workflow, which means our third and final activity (another LoggerActivity) will not execute.

Sure enough, running this code produces the following output:

Alright, so creating a handler for UnhandledExceptions in a WorkflowApplication is all well and good, but what if we want more control over how exceptions are handled? What if we want to handle specific exceptions? One solution is to create a base activity for our workflow as a TryCatch object, which inherits from the NativeActivity and allows for explicit catch blocks to be specified in response to exceptions thrown during execution of the workflow. The CreateTryCatchSequence() method shows how to create such an entity:

As you can see, we have a TryCatch object as our main Activity, which tries to create a Sequence object just as we saw before. This also contains three different activities, the second of which throws a System.Activities.ValidationException. The key difference is that the TryCatch object contains a Catches collection, where we can specify new Catch<T> elements that indicate what type of Exception should be caught, and what action to perform when doing so. We have two different catches, so the ActivityAction<T> for each corresponds to the appropriate type of exception we’re handling.

You may also notice that we instantiated a few local variables at the top of this method, which were DelegateInArgument<T> instances that we can then pass as Arguments to the ActivityAction<T> elements. Doing so allows the Handler of each action to use that localized Argument object to capture the contextual exception that was caught. Attempting to forgo the Argument = validationException assignment produces a System.Activities.InvalidWorkflowException, because the ActivityAction<T> has no runtime context while it is executing. This means it cannot access locally-scoped variables, like validationException, unless it is provided as an Argument, giving it the local context it needs to be used by the Handler property.

Finally, we have a, well, Finally element, which we assign to a single LoggerActivity to provide another output message. We finish it all off by invoking our TryCatch sequence with WorkflowInvoker.Invoke(). As expected, executing this method results in the following output:

To get the most out of your own applications and to fully manage any and all .NET Exceptions, check out the Airbrake .NET Bug Handler, offering real-time alerts and instantaneous insight into what went wrong with your .NET code, along with built-in support for a variety of popular development integrations including: JIRA, GitHub, Bitbucket, and much more.