Best Practices for Creating Custom Activities in SharePoint 2010

Summary:  Learn how to efficiently build custom activities for Microsoft SharePoint 2010 workflows. Start with the key components of workflows and activities, and then focus on best practices for building, deploying, and managing custom activities.

Applies to: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Provided by:  Keenan Newton, Microsoft Corporation

Contents

  • SharePoint 2010 workflows

  • SharePoint 2010 activities

  • Creating custom activities in SharePoint 2010

  • Best practices for creating custom activities in SharePoint 2010

  • Conclusion

  • Additional Resources

SharePoint 2010 workflows

In a general sense, a workflow is a process that determines how business works for a particular area or concern. For example, to submit expense reports, employees might have to print a standard form, take it to their manager for signature, and then deliver it to Human Resources for payment.

Most workflows have some degree of automation, where technology supports and speeds the interactions between people and their content. Two common automated workflows in most companies are the processes for new employee orientation and document review.

A SharePoint workflow, then, can be defined as an automated process that:

  • Streamlines how people work with content (for example, review, modify, and then publish).

  • Relies primarily on Microsoft SharePoint Foundation 2010 to support functionality, such as storage, security, management, and notification.

For example, Figure 1 shows the SharePoint workflow for submitting expense reports electronically.

Figure 1. Automated workflow for submitting expense reports

Automated workflow for submitting expense reports

There are two types of SharePoint workflows, sequential and state machine.

  • Sequential workflow. In the sequential workflow, steps are executed sequentially. Therefore, a sequential workflow always progresses forward; it never goes back to a previous step.

  • State machine workflow. A state machine workflow has no directional constraints; it moves from one state (step) to another until the logic concludes, completing the workflow. Therefore, a state machine workflow is executed in no particular order.

SharePoint 2010 activities

An activity is a portion of work that is completed with the help of other resources. Activities are the basic building blocks of workflows. A workflow can be created by using a single activity or a group of activities. SharePoint 2010 enables both out-of-the-box and custom activities. Out-of-the-box activities can be used directly in Microsoft SharePoint Designer 2010; custom activities require some coding.

Out-of-the-box activities

Standard, out-of-the-box activities include sending an email message, checking a list item in or out, and assigning a to-do item. These and other activities are available with SharePoint Designer 2010. See Workflow actions in SharePoint Designer 2010: A quick reference guide for a complete list of out-of-the-box activities.

Custom activities

With a wide selection of out-of-the-box activities, why are custom activities needed at all? This question is especially relevant when you consider that it is also fairly easy to execute code in an existing workflow by adding a CodeActivity and then writing the code in the ExecuteCode event handler. However, custom activities are especially helpful because they wrap custom code in a reusable component. Further, as the following examples show, some essential actions require more functionality than out-of-the-box activities can provide.

  • Looping. Out-of-the-box activities cannot provide direct looping support through collections, such as the lists in a site or the items in a list.

  • Accessing outside content. With out-of-the-box activities, it is not possible to access SharePoint content in other sites or site collections or to access anything at the farm or web application level.

  • Calling across the network. Standard actions do not support calling a remote web service from a SharePoint Designer 2010 workflow.

  • Running with elevated permissions. Out-of-the-box activities run under the current user’s identity and permissions. Although Impersonation steps can help mitigate this, workflow actions are still restricted from running under a more privileged user’s identity and elevated permissions.

  • Obtaining control at the workflow level. By its nature, SharePoint Designer 2010 insulates the workflow builder from the details of the underlying SharePoint workflow architecture.

Components of custom activities

Custom activities in SharePoint workflows are created in the same manner that user controls are created in .NET Framework applications. Custom activities are classes that inherit from a base class called Activity and defined in namespace System.Workflow.ComponentModel. A custom activity usually has the following components:

  • Definition. The definition is the required attribute of an activity where properties, events, and other values are defined.

  • Validator. The validator is used to validate the values of input properties.

  • Executor. The executor is used to execute the custom code in the activity.

  • Toolbox. The Microsoft Visual Studio 2010 toolbox helps to assign default values to properties when they are dragged to the Visual Studio 2010 designer surface.

  • Designer. The Visual Studio designer surface can help you create an effective user interface for the activity.

The specific workflow requirements determine what other components a given custom activity might include beyond these core components.

Categories of custom activities

As shown in Figure 2, custom activities can be categorized according to type (basic or composite), method of deployment, or method of initiation. The following subsections discuss these categories in greater detail.

Figure 2. Categories of custom activities in a SharePoint workflow

Categories of custom activities in a workflow

Types

There are two types of custom activities: basic and composite.

Basic activity

In basic, or simple, activities, all logic and execution are encapsulated in the code. Examples include the SendEmail activity in the Microsoft Windows software development kit (SDK) or an activity to query data from a database. Simple activities are used to execute discrete tasks.

Composite activity

In composite activities, the outcome depends on how the child activities are executed. The workflow itself is a composite activity that contains all other activities in that workflow. Composite activities serve as a grouping mechanism and can contain multiple activities. The Sequence activity is one example.

Deployment in SharePoint 2010

A custom activity can be deployed in a SharePoint environment in two forms: full-trust and sandboxed.

Full-trust activity

A full-trust custom activity is deployed as a farm solution. To use these activities in SharePoint Designer 2010, you must create and deploy a workflow actions file to package the activity, and an authorized type entry for the activity class must be added to the Web.config file. Making a call to a custom database or an external web service is an example of a process that requires creating a full-trust custom activity in Visual Studio.

Sandboxed activity

A sandboxed custom activity is deployed as a sandboxed solution. This lets users upload the solution by using a web interface, instead of relying on administrators. Sandboxed custom activities are limited from some actions, including making web service or database calls, interacting with external data, and impersonating a user who has elevated permissions.

Initiation

An activity can be started in two ways: synchronously or asynchronously.

Synchronous activity

Synchronous activities complete their work in a simple, linear manner. Users must wait for one process to complete before they start another. For example, the Delay activity is a synchronous activity that requires users to wait until it finishes before the next activity can be executed.

Asynchronous activity

Asynchronous, or event-based, activities start their work and then wait for a response. Or, they listen for an external event to be raised and then start their work. Users do not have to wait for one process to complete before they start another. Asynchronous activities are helpful for implementing functionality where a large amount of processing must be done on an object.

Creating custom activities in SharePoint 2010

You can create custom activities and conditions, and then associate them with SharePoint Designer 2010 by making them available on the Workflow Actions list. The ensuing screen shots and code examples outline the processes for the following tasks:

  • Creating a custom activity for a sandboxed solution by using Visual Studio 2010.

  • Making the activity available to SharePoint Designer 2010.

Figure 3 shows the solution structure of the SharePoint project that creates the custom activity.

Figure 3: Solution structure displayed in Visual Studio 2010

Solution structure displayed in Visual Studio 2010

The activity, called CreateSiteAction.cs, contains the following code example, which creates a site in SharePoint 2010.

class CreateSiteAction
{
public Hashtable CreateSite(SPUserCodeWorkflowContext context, string siteName)
{
Hashtable results = new Hashtable();
try
{
using (SPSite site = new SPSite(context.CurrentWebUrl))
{
using (SPWeb web = site.OpenWeb())
{
web.Webs.Add(siteName,"Trip Report: " + siteName,string.Empty,1033,"STS",false,false);
}
}
results["success"] = true;
results["exception"] = string.Empty;
}
catch (Exception e)
{
results = new Hashtable();
results["exception"] = e.ToString();
results["success"] = false;
}
return results;
}
}

The Elements.xml file (.ACTIONS file), called CreateSiteActionDefintion, contains the properties of the custom activity, such as Name, Category, and Assembly (Figure 4). Note that you can also create a custom activity at the farm level. In this case, the SandBoxFunction=”true” tag (highlighted) is removed.

Figure 4: Custom activity properties, as defined in the .ACTIONS file

Custom activity properties, as defined in ACTIONS

Using Visual Studio 2010, you can deploy the solution directly to a website or manually package it as a .WSP file and upload the file to the solution gallery of a SharePoint site. After you deploy and activate the sandboxed solution in the website, the Create Site action becomes available in the Sandboxed Workflow Actions category (Figure 5).

Figure 5: Accessing a custom activity in SharePoint Designer 2010

Accessing a custom activity in SharePoint Designer

When you begin to create a workflow, the new custom activity appears as a SharePoint Designer tag (Figure 6). This custom activity now can be used anywhere in the workflow.

Figure 6: Custom activity available for reuse in a workflow

Custom activity available for reuse in a workflow

Best practices for creating custom activities in SharePoint 2010

This section discusses best practices for creating custom activities in SharePoint 2010. These best practices are grouped into four categories: architecture, implementation, deployment, and adoption.

Best practices for architecture

Architectural best practices focus on solution architecture, base classes, and design.

Solution architecture

Select the best solution architecture (sandboxed or full-trust) for the workflow.

Custom activities that are created by using Visual Studio 2010 must be sandboxed or full-trust solutions. In the sandboxed architectural approach, you build custom activities, load them with partial trust, and then run them in the sandboxed solution. In the full-trust architectural approach, you develop full-trust actions by creating custom activity classes first.

Note

The restrictions for using the sandboxed solution architecture are discussed in Restrictions on Sandboxed Solutions in SharePoint 2010.

Base classes

Select the correct base classes to be inherited.

Out-of-the-box activities

Use SharePoint Designer 2010 to create a workflow from available out-of-the-box activities, which eliminates the need to write code. This approach provides the following advantages:

  • You can develop and test the workflows quickly.

  • Because you create these workflows by using rules and declarative code, they can be deployed to servers where administrative policy prohibits custom code assemblies.

This approach has some limitations, including the following:

  • Because you create the workflow directly against a list, it is associated with the list at the time of design. Therefore, there is no association stage with workflows created in SharePoint Designer 2010.

  • Workflows created in SharePoint Designer 2010 cannot be modified.

  • You cannot create a workflow against a content type in SharePoint Designer 2010.

CodeActivity

When you must write code, deriving the code from CodeActivity provides the following advantages:

  • It executes in a single pulse.

  • It does not have to schedule other activities.

  • It does not have to have advanced Workflow Runtime features.

  • It does not have to execute asynchronously.

The following code example shows basic code that is derived from CodeActivity.

public class BadReadLine: CodeActivity<string>
    {
        protected override string Execute(CodeActivityContext context)
        {
            return Console.ReadLine();
        }

If you cannot create the logic by composing other activities, you can write a code-based activity. To write activities in code, you must derive from the appropriate class, define arguments, and then override the Execute method.

Most custom activities are derived from AsyncCodeActivity, CodeActivity, NativeActivity, or one of the generic variants. Alternatively, the activity can be modeled declaratively. At a high level, the four base classes can be described as follows:

  • Activity. Used to model activities by composing other activities, usually defined by using XAML.

  • CodeActivity. Used to write basic code quickly (simplified base class).

  • AsyncCodeActivity. Used when the activity must perform some work asynchronously.

  • NativeActivity. Used when the activity needs access to runtime internals (for example, to schedule other activities or to create bookmarks).

Design

There are several best practices to consider when you design a custom activity.

Arguments versus Activities versus Properties

Consider the purpose of an expression when you decide to use arguments, activities, or properties. It is preferable to use the following:

  • Argument for expressions that are evaluated one time before executing the activity (for example, If.Condition or WriteLine.Text).

  • Activity<TResult> for expressions that might be evaluated multiple times (for example, While.Condition)

  • CLR Property for expressions that do not change for all instances of an activity (for example, InvokeMethod.MethodName).

Body versus Children

Determine if the activity schedules a single child or multiple children. It is preferable to do the following:

  • Use a Body property in an activity that schedules a single child (for example, While, CancellationScope, or TransactionScope).

  • Use a Children property in an activity that coordinates running its children (for example, Sequence or Parallel).

Variables

Use variables to maximize flexibility in more complex activities. It is preferable to do the following:

  • Add a Variables collection to an activity that needs to enable data sharing among its children (for example, Sequence or Pick).

  • Use ImplementationVariables to store an internal state in an activity. For example, suppose that you have a list of activities and have to keep track of where you are. By using ImplementationVariables, you can have a counter that traces the child activities that are currently running without surfacing it to the end user.

See Authoring Custom Control Flow Activities in WF 4 for code examples that execute these and other design best practices.

Best practices for implementation

Implementation best practices focus on naming conventions, event receivers, and the Execute method.

Naming conventions

Create a Dependency property by adding the keyword Property to the end of the name of the actual property. In the following example, the Dependency property for a parameter (called originCityCode) is defined in the custom activity class.

public static DependencyProperty originCityCodeProperty = DependencyProperty.Register("originCityCode", typeof(string), typeof(CustomActivity));
[DescriptionAttribute("get and sets the value of the city code of origin city")]

Dependency properties indicate that the workflow depends on this value. All values that are used as inputs or outputs for the custom workflow activity should be marked as dependency properties.

Event Receivers

When you create tasks, or update list items or site content by using SharePoint-specific workflow services, do not instantiate SPWeb, SPSite, SPList, or SPListItem objects in an event receiver. Event receivers that instantiate these objects instead of using the instances passed through the Event properties can cause the following problems:

  • They incur significant additional round trips to the database. For example, one write operation can result in up to five additional round trips in each event receiver.

  • Calling the Update method on these instances can cause subsequent Update calls in other registered event receivers to fail.

The following code example shows a sample implementation of the Execute method that uses SharePoint services to log comments to the workflow history list.

protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
        {
            // get reference to SharePoint Service
            ISharePointService SPService = (ISharePointService)context.GetService(typeof(ISharePointService));
            // use SharePoint Service to perform work
            SPService.LogToHistoryList(this.WorkflowInstanceId,
            SPWorkflowHistoryEventType.WorkflowComment,
            this.UserId,
            TimeSpan.MinValue,
            "The 'Hello World' activity",
            "My description",
            "My custom data");
            // return Closed to indicate the activity has completed
            return ActivityExecutionStatus.Closed;

Execute Method

The Execute method must complete by returning a value from the ActivityExecutionStatus enumeration. Enumeration of activity status values corresponds to the life cycle of an activity in a running workflow instance. The following table shows different enumerations for custom activities.

Member

Description

Initialized

Represents the status when an activity is being initialized.

Executing

Represents the status when an activity is executing.

Canceling

Represents the status when an activity is in the process of being canceled.

Closed

Represents the status when an activity is closed.

Compensating

Represents the status when an activity is compensating.

Faulting

Represents the status when an activity is faulting.

Once execution of the code is complete, you must call the enumeration Closed for the activity.

Best practices for deployment

Deployment best practices focus on using the authorizedType entry and a strong name.

AuthorizedType entry

To make a full-trust workflow activity available to declarative workflows, add an authorizedType entry to the Web.config file for the content web application. This gives your custom activity the same status as the built-in workflow activities that are included with SharePoint 2010. The following code example shows the format of an authorizedType entry.

<configuration>
    <System.Workflow.ComponentModel.WorkflowCompiler>
      <authorizedTypes>
        <!-- authorized type entries for standard actions and conditions -->
        <authorizedType Assembly="CustomActions, [full four part assembly name]"
              Namespace="CustomActions"
              TypeName="*"
              Authorized="True" />
      </authorizedTypes>
    </System.Workflow.ComponentModel.WorkflowCompiler>
  </configuration>

Full-trust activities do not appear in SharePoint Designer 2010 unless a custom authorizedType element is added to the authorizedTypes section of the Web.config file.

Strong name

Sign a custom workflow condition assembly (also called a Class Library Assembly) with a strong name so that it can be installed in the global assembly cache (GAC) and used by SharePoint Designer 2010. A strong name consists of the assembly’s identity—its simple text name, version number, and culture information (if provided)—plus a public key and a digital signature.

Best practices for adoption

Adoption best practices focus on object disposal, runtime, and performance.

Disposal of SharePoint objects

Dispose of SharePoint objects when you no longer need them. It is common practice for any SharePoint code to dispose of objects that are not being used.

Runtime

During runtime, consider the following points for optimal execution.

Blocking calls

Do not make blocking calls in an activity. A workflow runs on a single thread, so if you write a blocking code, it will block that single thread. For example, suppose that you want to add Console.Readline in your workflow. You create the activity derived from CodeActivity and write the code for Console.Readline in it. When you add this activity to your workflow and execute it, it blocks other activities that might be working in parallel, thus preventing other work items from executing.

I/O Operations from the Scheduler Thread

No matter when an asynchronous I/O executes, whether through files, classes, or web services, the I/O occurs on an I/O thread. Therefore, when you call the asynchronous operation, it is executed on the I/O thread and freezes the scheduler thread.

Serializable arguments and variables

Ensure that all argument and variable types are serializable (except for a specialized type that is used only in a NoPersistZone). If all arguments and variables are not serializable, the workflow is persisted and throws an exception.

Cancelation

If the operation that is being performed can be canceled, support the cancelation with the activity.

Performance

To ensure high-functioning performance, consider the following best practices:

  • Override CacheMetadata to avoid reflection. CacheMetadata is the method where an activity introduces itself at runtime. If it is not overridden, it is falsely implemented by using reflection.

    protected override void CacheMetadata(NativeActivityMetadata metadata)
            {            
                RuntimeArgument arg = new RuntimeArgument("Condition", typeof(bool), ArgumentDirection.In);
                metadata.AddArgument(arg);
                metadata.Bind(this.Condition, arg);
    
                metadata.AddChild(this.Then);
    metadata.AddChild(this.Else);    
    }
    
  • Cache callback delegates if arguments or variables are to be used multiple times.

  • Limit access to variables. If you use a variable multiple times, use the Get method.

  • Use a tight scope when you declare variables; that is, declare a variable wherever it is to be used.

Conclusion

With custom activities in SharePoint 2010, you can provide benefits not only for your organization’s end users, but also for the IT department. Robust SharePoint workflows enable users to access critical business data and increase efficiency. Likewise, IT is able to transition from tactical support work to more strategic initiatives that grow business.

Moreover, by creating custom activities, you can improve the reusability and maintainability of your code. The value of these benefits cannot be overstated in terms of the rapid launch and long-term usefulness of solutions. Because code can be reused, custom activities simply can be dropped into other workflows, which then can be executed quickly. Further, because code is split into various activities (classes), workflow templates are neatly contained, without thousands of lines of code. This makes it much easier to maintain a solution over a longer period of time.

Additional Resources

For more information, see the following resources: