Activity Authoring Options in WF

.NET Framework 4.6.1 provides several options for creating custom activities. The correct method to use for authoring a given activity depends on what run-time features are required.

Deciding Which Base Activity Class to Use for Authoring Custom Activities

The following table lists the features available in the custom activity base classes.

Base activity class Features available
Activity Composes groups of system-provided and custom activities into a composite activity.
CodeActivity Implements imperative functionality by providing an Execute method that can be overridden. Also provides access to tracking, variables, and arguments..
NativeActivity Provides all of the features of CodeActivity, plus aborting activity execution, canceling child activity execution, using bookmarks, and scheduling activities, activity actions, and functions.
DynamicActivity Provides a DOM-like approach to constructing activities that interfaces with the WF designer and the run-time machinery through ICustomTypeDescriptor, allowing new activities to be created without defining new types.

Authoring Activities using Activity

Activities that derive from Activity compose functionality by assembling other existing activities. These activities can be existing custom activities and activities from the .NET Framework 4.6.1 activity library. Assembling these activities is the most basic way to create custom functionality. This approach is most typically taken when using a visual design environment for authoring workflows.

Authoring Activities using CodeActivity or AsyncCodeActivity

Activities that derive from CodeActivity or AsyncCodeActivity can implement imperative functionality by overriding the Execute method with custom imperative code. The custom code is executed when the activity is executed by the runtime. While activities created in this way have access to custom functionality, they do not have access to all of the features of the runtime, such as full access to the execution environment, the ability to schedule child activities, bookmark creation, or support for a Cancel or Abort method. When a CodeActivity executes, it has access to a reduced version of the execution environment (through the CodeActivityContext or AsyncCodeActivityContext class). Activities created using CodeActivity have access to argument and variable resolution, extensions, and tracking. Asynchronous activity scheduling can be done using AsyncCodeActivity.

Authoring Activities using NativeActivity

Activities that derive from NativeActivity, like those that derive from CodeActivity, create imperative functionality by overriding Execute, but also have access to all of the functionality of the workflow runtime through the NativeActivityContext that gets passed into the Execute method. This context has support for scheduling and canceling child activities, executing ActivityAction and ActivityFunc<TResult> objects, flowing transactions into a workflow, invoking asynchronous processes, canceling and aborting execution, access to execution properties and extensions, and bookmarks (handles for resuming paused workflows).

Authoring Activities using DynamicActivity

Unlike the other three types of activity, new functionality is not created by deriving new types from DynamicActivity (the class is sealed), but instead, by assembling functionality into the Properties and Implementation properties using an activity document object model (DOM).

Authoring Activities that Return a Result

Many activities must return a result after their execution. Although it is possible to always define a custom OutArgument<T> on an activity for this purpose, it is suggested to instead use Activity<TResult>, or derive from CodeActivity<TResult> or NativeActivity<TResult>. Each of these base classes has an OutArgument<T> named Result that your activity can use for its return value. Activities that return a result should only be used if only one result needs to be returned from an activity; if multiple results need to be returned, separate OutArgument<T> members should be used instead.