Chapter 8. Creating Workflows in WSS

by Robert Bogue

Wow! That's all you can say when you look at the capabilities of Windows SharePoint Services 3.0 (WSS 3.0) and Microsoft Office SharePoint Server 2007 (MOSS 2007) — particularly when you evaluate the product's capability to facilitate, coordinate, and track business processes in your enterprise. Although the "SharePoint Vision" has always been about providing more connectivity with Office documents between people, between steps, and between systems, SharePoint has made significant progress in this regard with the latest release compared to previous releases, and when compared to competitive products.

This chapter covers a lot of ground as I help you to understand the options for creating workflows, the fundamentals of workflow, the limitations of workflow, and some ways to make workflow work for your organization.

Largely, this chapter won't be covering how to use Microsoft's Windows Workflow Foundation (WF), upon which SharePoint's workflow functionality is based. Some essential topics are covered only enough to place the SharePoint implementation of WF into perspective. If you need a comprehensive reference to WF, you'll want to pick up another book on workflow, such as Professional Windows Workflow Foundation by Todd Kitta (Wiley Publishing, Inc., 2007).

What Is a Workflow?

A workflow is a set of reactions to a set of external stimuli. The first stimulus is "start," but there may be many more stimuli during the workflow that control how the workflow responds. Approval workflows respond to the request to start an approval process, and then each approval (or rejection) causes the workflow to flow down a different path.

Inherent in the WF perspective of workflows is that they have built in long (in computer terms) delays. The fundamental assumption is that workflows are connecting systems to humans, or humans to humans. This means a relatively large number of workflow instances (individual workflows), and that they may be running for days, weeks, or months. As a result, workflows (from a WF perspective) must be the following:

  • Serializable — They may be taken from memory when a server reboots, a process ends, or some finalizing event occurs. This requires converting the memory representation of the workflow into a persistable stream that can be written out and saved for later. This is sometimes called dehydration.

  • Resumable — Capable of being resumed based on new stimuli. When the file is updated, users indicate that they want to interact with the workflow. Or, if a timer expires, the workflow must be reserialized into running memory and activated with the event. This is sometimes called rehydration.

Though it's possible to work with workflows that do not need to be serialized or resumed because they consume only a single, start stimuli, these sorts of workflows do not capture the true power of the WF.

Workflow Options

Perhaps the greatest opportunity with SharePoint technologies and workflow exists within the flexibility you have to create workflow solutions. Specifically, you can create workflow solutions by:

  • Using Microsoft Office SharePoint Designer 2007

  • Customizing out-of-the-box (included) workflows

  • Utilizing manual processes

  • Writing event receivers with Visual Studio (VS)

  • Writing custom workflows with VS

Each of these is a valid option when developing solutions with SharePoint that "require" a workflow. Some options are repeatable and reusable, whereas others are quick to get up and running, and don't replicate well. Let's investigate each one in enough detail that you can make an appropriate decision about which solution is correct for your situation.

Manual Workflow

Manual workflows are just that — manual. In other words, you didn't implement any of SharePoint's workflow features. Users are expected to manage the flow of information themselves. It may seem odd to start off a discussion about workflow features by suggesting that you don't use them — and it is. However, it may be a reality in your organization. Workflows are useful for generating highly repeatable processes. This may or may not be necessary for the business need that you're seeking to use workflow for. If the need for consistency doesn't have a strong business driver, it may make sense to use out-of-the-box features such as alerts to alert people that action needs to be taken, rather than creating a more formal workflow.

Obviously, the benefit to this solution is that there's no workflow development time. The downfall is that it doesn't provide much (if any) support for the process.

Out-of-the-Box Workflows

WSS 3.0 ships with one workflow (Three-State) and MOSS 2007 ships with several more. These workflows are what would be considered data-driven workflows. That is, the way that they work is fundamentally based upon the data that they are provided. In this case, the way that you set up the workflow when it is associated with the list (or document library) controls the people who are involved with the workflow — and, to some limited extent, how the workflow operates.

The opportunity here is to use these out-of-the-box workflows with your custom data (such as who will perform approvals) to solve your workflow needs. This is a great option if you want the power of a workflow, but aren't able to develop (or interested in developing) your own.

The benefit of this approach is that it doesn't require development of your own custom workflow. However, it is severely constrained by the fact that your flexibility is limited to the flexibility specifically designed in the out-of-box workflows that Microsoft shipped with the product. This is definitely the first option to pursue, if you can find a workflow that you can customize to your needs.

SharePoint Designer 2007

With a clear focus on being the information worker's way to customize SharePoint, SharePoint Designer (SPD) takes the best of customizing SharePoint with the FrontPage 2003 product, and rolls in new functionality around the creation of workflows and management of SharePoint in general. From a workflow perspective, SPD provides a simplified "rules-based" workflow editing tool, much like you'll find while working with Outlook rules for your mail. This simplified view makes it ideal for workflows that information workers are creating.

SPD-developed workflows are good solutions in many ways, because information workers can be trained on how to create their own workflows. These workflows generally can be done very quickly by IT professionals. As a result, they require the least amount of time to develop of any custom workflow solution option that SharePoint supports. However, this ease of use comes with two costs.

First, the workflows created with SPD don't have the same options that a complete custom workflow might have. Only workflow activities that are marked as safe for SPD use are available in this context. Though these limits may not be felt with simple workflows, any truly complex workflows that are designed to support a business process may find the restrictions to be limiting.

Second, SPD workflows cannot be reused from one list to another — or one site to another. The one way around this is to template the list on which the workflow is based. Lists created from that template will inherit the workflow. Although this is certainly a workable solution in some situations, the limit that the workflow can't be applied to an existing list may be too restrictive for your organizational needs.

Event Receivers

When reading the earlier discussion about what a workflow is, you learned that workflows must be serializable and resumable. They must be able to start and stop, and start again, based on their need for new stimuli. Sometimes, however, workflows can be used when this is not the case. All of the responses from the workflow take place because of the initial start stimuli. Though this is a perfectly acceptable use of the WF that underpins SharePoint, these sorts of workflows are equally suited to be handled by event receivers.

Event receivers (which were present in WSS 2.0) have been radically improved for WSS 3.0. WSS 2.0 supported only asynchronous events — that is, events that occurred after the event had completed. It only supported those events for document libraries. WSS 3.0 supports both synchronous (occurring before the operation is complete) and the asynchronous events supported in WSS 2.0. Furthermore, these events are supported for every list — not just document libraries.

Event receivers are a good option for workflows that don't need to respond to multiple stimuli because there is less you need to know to write an event receiver than you need to know to effectively create custom workflows. Of course, event receivers aren't suitable for situations that require multiple interactions with a single item in the context of one larger workflow because they aren't workflows, but rather simple responses to events.

Custom Workflows with Visual Studio

When the other options won't work and you're willing to make the investment to learn the WF infrastructure and how SharePoint interacts with that infrastructure, you're ready to create custom workflows with Visual Studio (VS) that you can deploy to SharePoint. The advantage of developing workflows with VS is that you have substantially fewer barriers preventing you from creating the precise workflow that the business needs. You have full access to every built-in workflow activity, as well as the ability to add code into the workflow as a separate activity, or to respond to events raised by the workflow activities. In addition, you can purchase third-party activities, or even write your own activities that plug directly into the VS design surface.

The negatives to developing custom workflows with VS are primarily that they are more complicated to get right and require more time to develop. However, the reward for the effort is a reusable workflow that can be attached to any list or library on any site where the workflow has been installed and activated. That means that an approval process that you design in the United States can be applied to your offices in the United Kingdom or wherever the workflow is needed. Custom workflows in VS are, in fact, the way that the out-of-the-box workflows were developed.

Because custom workflows (or, more precisely, custom workflow templates) developed in VS are so powerful, the rest of this chapter is dedicated to getting you what you need to know to develop custom workflows with VS.

SharePoint Background

Before I can effectively walk you through creating a custom workflow, you must understand what you can associate a workflow with, and how SharePoint's core features mesh with workflows.

Lists and Libraries

Perhaps the most common way to use a workflow is to associate it to a list or library in SharePoint. In fact, all libraries in SharePoint are themselves lists. Thus, the most common way to use workflows in SharePoint is to associate the workflow with a list (even if that list happens to be a library). Workflows can also be associated with content types.

Content Types

Back in SharePoint Portal Server 2001 (SPS 2001), you had the ability to define different types of documents that were stored in a document library. Each document type had its own fields — metadata about the document. WSS 2.0 and Microsoft Office SharePoint Portal Server 2003 (SPS 2003) removed this functionality from the product because of the effort to re-platform against SQL Server instead of the Web Storage System (essentially the Exchange data store). This brought a great deal of angst from customers as they tried to store different kinds of documents in their document libraries — each document type requiring a few different fields, some of which were required only for certain document types.

WSS 3.0 solves this need by reestablishing the idea that you can store different kinds of data in a list (and, therefore, a library). Each type of data is given a content type. The content type bundles the fields as well as the workflows to be associated with that kind of data. Multiple content types can be bound to a single list and, therefore, it's possible to have different rules for different types of data, both in terms of the fields that are included and the workflows the item goes through.

Content types are essential to understanding how SharePoint implements workflow because when SharePoint creates an item from a workflow, it does so via the content type. In particular, tasks created by SharePoint (whether through the CreateTask or CreateTaskwithContentType activities) are assigned a content type. This is used to control what fields are available and what fields are displayed to users when they display or edit the item.

Universal Logging Service

The SharePoint Universal Logging Service (ULS) is a centralized spot where all of SharePoint's internal operations log their successes and failures. The log files are created on each member of the farm in their local C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions12LOGS directory. Each individual log file is created with the format of SERVERNAME-DATE-TIME, where SERVERNAME is the name of the server the log file was created on and for which events were captured. DATE is the date the log file was created in the format of the four-digit year, the two-digit month, and the two-digit day. The final element is TIME in 24-hour format, with a two-digit hour, followed by the two-digit representation of the minutes past the hour.

Because workflows don't interact directly with the user and there is often not a place to surface exceptions to the user interface, you'll find a large number of helpful (and not so helpful) exceptions end up here for you to review. The question isn't whether you'll need to look at the ULS log files while developing a SharePoint workflow; it's a question of when you'll need to do it and how often.

These files are much like most other log files you've seen in your career — with one exception. The individual entries may be split across multiple lines. Longer messages, particularly those containing exception details, get split into multiple lines within the file after just shy of 1,000 characters.

The Feature Mechanism

There's actually a mechanism in SharePoint called a Feature. That is, you create features that are deployed as a Feature to SharePoint. Are you confused yet? The key to this concept is understanding that there's a specific thing in SharePoint called a Feature, and it's used to "light up" new functionality within a site, site collection, Web application, or SharePoint farm. Chapter 4 provides more information about Features.

Filling the Toolbox

To develop workflows with SharePoint, you'll need two key pieces in addition to WSS and VS 2005 Professional:

  • Visual Studio Extensions for .NET 3.0 (Windows Workflow Foundation) — This package includes the extensions to VS to allow for the design and debugging of workflows that use the Windows WF. It's available for download at http://www.microsoft.com/downloads/details.aspx?familyid=5D61409E-1FA3-48CF-8023-E8F38E709BA6&displaylang=en.

  • Windows SharePoint Services SDK — The WSS SDK includes the additional SharePoint activities, snippets, and project templates to make it easier to build and deploy SharePoint workflows. It's available at http://www.microsoft.com/downloads/details.aspx?familyid=05e0dd12-8394-402b-8936-a07fe8afaffd&displaylang=en.

If you're working with MOSS 2007, you can download that SDK instead of the WSS SDK. It is available at http://www.microsoft.com/downloads/details.aspx?familyid=6D94E307-67D9-41AC-B2D6-0074D6286FA9&displaylang=en. Note that if you do use the MOSS 2007 SDK instead of the WSS SDK, you'll find that it creates a completely different deployment model for workflows. Because of this, in the sections that follow, the steps walking you through how to modify the deployment of your workflow won't work. If you want to follow along step-by-step, you'll need to use the WSS SDK.

Before leaving the things that you need in your toolbox, you should definitely get a copy of Fiddler from www.fiddlertool.com. Fiddler is a transparent HTTP proxy that allows you to see and break apart the HTTP traffic between the browser and the Web server. If you start working with Workflow Association and Workflow Instantiation forms, it will be invaluable in making sure that the form-posted variables are correct.

Creating a Workflow

That's enough of the theory and background. It's now time to start developing a workflow.

In this example, you build a student Grades workflow. The Grades workflow is designed to activate whenever a document is uploaded to a specific document library. A task is added to the task list that the students don't have access to. The workflow can add to this list because it runs as a special system account. Instructors and assistants subscribe to alerts on the task list and, in that way, are informed that a new assignment is ready to be graded. When the instructor or assistant has reviewed the assignment, they enter a numeric score, as well as notes on the score, into the task. This is copied back into the document in a set of fields that cannot be modified. In a real-life situation, you might add integration to a grade book program to add the grades. However, this example demonstrates the following core concepts with workflows:

  • Content Types — I illustrate the use of content types to create a custom task type, as well as creating fields that cannot be edited.

  • Task Creation — Creating a task in a SharePoint workflow isn't as easy as dropping an activity on the design surface. Because this workflow relies upon tasks to take instructor input, I walk you through the creation of tasks step-by-step.

  • Property Modification — I show you how to make changes to the workflow item while the workflow is running.

Content Types

As mentioned previously, every piece of information in SharePoint has a content type. The content type defines the fields that are associated with the content. It is possible, as is the case in lists, to add additional fields beyond the base content type. However, the best way to ensure that a field is present is to define a content type and activate it in the list you want your content in.

A content type can also inherit from other content types. For example, the default workflow task, which is used by default to create tasks from a workflow, derives from the standard task content type. In this example, I derive from the workflow content type for the content types.

The definition of content types consists of three basic pieces: field definitions, field references, and the Feature that you deploy them in. Let's start by defining two fields in XML. These will go into a file used in the Feature that I discuss later in this chapter.

<Field ID="{0116A5FF-6FB7-43e1-B3E3-30A58B40349C}"
     Name="GradingScore" Group="Grading" DisplayName="Score"
     Type="Number" Sealed="FALSE" ReadOnly="FALSE" Hidden="FALSE"
     DisplaceOnUpgrade="TRUE"/>
<Field ID="{81792580-6F97-4960-84C2-7A8A926D1DCE}"
     Name="GradingNotes" Group="Grading" DisplayName="Notes"
     Type="Text" Sealed="FALSE" ReadOnly="FALSE" Hidden="FALSE"
      DisplaceOnUpgrade="TRUE"/>

Let's walk through each of the attributes:

  • ID — A unique GUID for the field. You can generate a GUID from VS by selecting Tools

    Content Types
  • Name — This is the internal name of the field in SharePoint. Care must be taken when naming fields so as not to collide with an internal name already used by SharePoint, or with the names of other fields on the system. Note that the fields in the preceding code snippet were prefixed with Grading for this reason. These names should not contain spaces or special punctuation.

  • Group — This is the grouping that will be used to organize fields in the user interface. This name can be anything that makes sense for the application.

  • DisplayName — This is the name that will be displayed to users when they see the field. This field may contain spaces and the special punctuation to make the field easy for users to understand.

  • Type — This is the type of the field to be created. Here I am using the Number and Text values but Boolean, Choice, Computer, Currency, DateTime, URL, and other field types can be used as described at http://msdn2.microsoft.com/en-us/library/ms437580.aspx.

  • Sealed — If true, then no one will be able to change the field in list settings. These fields are set to be modifiable.

  • ReadOnly — The field itself can be written to. If you don't set this to false (or omit it to accept the default), the field won't show up in the user interface.

  • Hidden — This determines whether or not the field is hidden. You might hide a field if you want to use it internally, but you don't want users to be able to see it.

  • DisplaceOnUpgrade — This setting indicates that, if the field definition already exists, you want to overwrite it with the values in this XML fragment.

With the fields created, the next step is to create the content type and add references to the fields. To add the content types, you must know how to derive from an existing content type. There's a base content type hierarchy in MSDN at http://msdn2.microsoft.com/en-us/library/ms452896.aspx. This shows us the content IDs for existing types. Unlike other IDs in SharePoint (which are either an integer or a GUID), the content type ID is a special hexadecimal string that represents not only the content type itself, but also its parent — sort of like a human's surname, except in more detail.

There are two mechanisms for creating a content type. The first mechanism is appending a two-digit ID after the existing content type. The two-digit ID can be anything except 00. This is generally reserved for content types derived from your own content types because the potential for collision is so high.

The other mechanism (which is recommended) is to use 00 followed by a GUID that has had all of its punctuation removed. This creates a longer content type ID, so it's recommended only for the first level that you derive from a system type. Thereafter, you should use the two-digit mechanism described previously in order to minimize the overall length of the content type, which is capped at 512 bytes (in other words, 1,024 hexadecimal characters). You can learn more about content type IDs in the Content Type IDs entry in MSDN available at http://msdn2.microsoft.com/en-us/library/aa543822.aspx.

The content type for the Grades workflow task looks like this:

<ContentType ID="0x01080100B7336179CFFE43e59B86E241C767010E"
     Name="GradingTask" Group="Grading" Description="Grading Task"
     Version="0" Hidden="FALSE" >
      <FieldRefs>
     <FieldRef ID="{0116A5FF-6FB7-43e1-B3E3-30A58B40349C}"
           Name="GradingScore" DisplayName="Score" />
     <FieldRef ID="{81792580-6F97-4960-84C2-7A8A926D1DCE}"
           Name="GradingNotes" DisplayName="Notes"/>
     </FieldRefs>
</ContentType>

Here, the "00+Guid" method of creating the content type was used because it's the first level from a system content type. The workflow task content type is 0x010801, thus that is how this content type begins. The XML fragment also contains <FieldRef> nodes that correspond to the fields defined earlier — both the ID and the Name fields match exactly.

The next content type is the content type for the document that will have the same score and notes fields, but this time they won't be editable. The document content type is as follows:

<ContentType ID="0x010100ADEC125AC3C74c1bA7E3A50731525809"
     Name="GradingDocument" Group="Grading" Description="Grading Document"
     Version="0" Hidden="FALSE" >
      <FieldRefs>
     <FieldRef ID="{0116A5FF-6FB7-43e1-B3E3-30A58B40349C}"
           Name="GradingScore" DisplayName="Score" ShowInDisplayForm="TRUE"
          ShowInFileDlg="FALSE" ShowInListSettings="TRUE" ShowInEditForm="FALSE"
          ShowInNewForm="FALSE" ReadOnlyClient="TRUE" />
     <FieldRef ID="{81792580-6F97-4960-84C2-7A8A926D1DCE}"
          Name="GradingNotes" DisplayName="Notes" ShowInDisplayForm="TRUE"
          ShowInFileDlg="FALSE" ShowInListSettings="TRUE" ShowInEditForm="FALSE"
          ShowInNewForm="FALSE" ReadOnlyClient="TRUE" />
     </FieldRefs>
</ContentType>

This document type is derived from a document (0x0101) with the same GUID method used earlier — but not the same GUID. The content type also includes the same fields as the task by creating <FieldRef> nodes that match ID and Name attributes to the <Field> nodes created earlier. In this case, however, the fields should not be able to be written to. There is a ReadOnly attribute for the <FieldRef>, but it causes the field to become hidden as well, so you can't use it. Instead, the field is prevented from displaying on the new and edit forms. Following are descriptions of the new attributes:

  • ShowInDisplayForm — The display form is the form that is displayed when the user elects to view the item, or view properties of a document. It is set to TRUE so that it will be displayed.

  • ShowInFileDlg — When an Office application saves the document, does the field show? It is set to FALSE, because the user isn't supposed to manipulate the value directly.

  • ShowInListSettings — Show the field in the list settings. If this is set to FALSE, the field will not be visible when changing the list. This value is TRUE so that the field will be displayed.

  • ShowInEditForm — The edit form is the one that a user gets when editing an item or editing properties on a document. Because the user shouldn't change the value, the attribute is FALSE.

  • ShowInNewForm — The new form is the one that the user gets when trying to create a new item. Because the user shouldn't ever set this value, the attribute is FALSE.

  • ReadOnlyClient — This attribute indicates that the client shouldn't be able to set the value of the field. This is TRUE to prevent client-side changes.

The content types are done. To deploy them, a SharePoint Feature is needed. Because the workflow will automatically create a Feature, let's use the workflow Feature to deploy content types at the same time.

Creating a Workflow Project in Visual Studio

As mentioned previously, you must install a few components to develop workflows with SharePoint and WF. Once those pieces are installed, an option to create a SharePoint Sequential workflow will appear, as shown in Figure 8-1. The Grades workflow will perform a few basic steps. It will create a task, wait for the task to change, change the document with some code, and delete the task.

The SharePoint Sequential Workflow selection

Figure 8.1. The SharePoint Sequential Workflow selection

To create the outline for the Grades workflow, follow these steps:

  1. Create a sequential workflow by selecting the SharePoint (for WSS) or SharePoint Server (for MOSS) folder under Visual C#. Give the project a name of Grades, and select a folder to put the project in.

  2. Once the project has been created, double-click the Workflow1.cs file from the Solution Explorer to show the workflow that was automatically created. Figure 8-2 shows what the workflow looks like as soon as it's created. VS has automatically created the workflow and added the required onWorkflowActivated1 activity as the first activity.

    The blank workflow template

    Figure 8.2. The blank workflow template

  3. From the toolbox, drag a CreateTask activity, an OnTaskChanged activity, a Code activity, and a DeleteTask activity (in sequence) to the design surface, as shown in Figure 8-3.

You may notice that there are little red exclamation points next to each of the four activities that you added to the design surface. That is because they all failed validation. The design interface is warning you that it knows, based on the current settings on the activities, that they won't work. Let's fix those errors and complete the workflow.

The "completed" workflow on screen

Figure 8.3. The "completed" workflow on screen

Completing the Create Task Activity

To get a CreateTask activity working, three things are needed: a correlation token, a task properties object, and a task guide. The easiest of these to take care of is the correlation token, which can be created with the following process:

  1. Click the createTask1 activity, then right-click and select Properties.

  2. In the Properties pane, select the CorrelationToken box, type in taskToken, and press Enter.

  3. Now, click the plus sign to the left of CorrelationToken and, in the OwnerActivityName line that appears, select Workflow1. VS has created a correlation token for you. Note that each item that will receive events must have its own correlation token. Thus, the task correlation token you created is different than the workflow correlation token that was created automatically when the project was created.

  4. Defining the task properties and the GUID are a bit more challenging. For that, you'll need to right-click the activity and select "view code." You need to add two lines underneath the lines that define the workflowId and workflowProperties. The lines will define the taskId and taskProperties like this:

    public Guid taskId = default(System.Guid);
    public SPWorkflowTaskProperties taskProperties =
         new SPWorkflowTaskProperties();
  5. Switch back to the Design view, which appears in the tabs as Workflow1.cs [Design].

  6. Click the createTask1 activity, right-click, and select Properties from the context menu.

  7. In the properties for createTask1, select TaskId, and then clicks the ellipsis (...) button that appears. This will raise a Bind dialog, as shown in Figure 8-4.

    The TaskId property becomes bound to the taskId variable

    Figure 8.4. The TaskId property becomes bound to the taskId variable

  8. Select the taskId property and click the OK button. You've just bound the taskId property to the taskId that you created.

  9. Perform Steps 7 and 8 again on the TaskProperties activity property and taskProperties workflow property.

  10. Next is setting the taskId correctly. To do this, code will be added to the MethodInvoking event. Double-click the createTask1 activity so that it creates the default event handler, which is MethodInvoking. Methods that end in "ing" happen before the main work of the activity, so you can use this method to set the taskId. You need to do this because, when you defined it earlier, you didn't give it a unique ID — you just gave it the default for a GUID (all zeros). Add the following line to the createTask1_MethodInvoking method that was created when you double-clicked:

    taskId = Guid.NewGuid();
  11. To set the task title to something meaningful, add the following line immediately following the line added in Step 10:

    taskProperties.Title = "Task for " + workflowProperties.Item.Name;
  12. Switch back to the Design view. You're finished with the createTask. The red exclamation point that was on it should be gone now. (Actually, it was gone early in the process when you set the correlation token.)

Completing OnTaskChanged

For the onTaskChanged1 activity, you have essentially the same properties to set. However, because they are already created, the process is much easier. In this case, the correlation token must be set, as well as the TaskId property. In addition, taskProperties is bound to AfterProperties so that the taskItemId value will be set.

  1. Select the onTaskChanged1 activity, right-click, and select Properties from the context menu.

  2. In the CorrelationToken field, click the drop-down list box arrow and select taskToken.

  3. Click the TaskId property field and then the ellipsis.

  4. Select taskId from the binding dialog and click the OK button.

  5. Select the AfterProperties field and click the ellipsis.

  6. Select taskProperties from the binding dialog and click the OK button.

The onTaskChanged activity is done. The red exclamation point should be gone for this activity, too.

Completing the Code Activity

The final activity is the code activity where you will copy the fields from the task back to the document.

Double-click the codeActivity1 activity to create a handler for ExecuteCode. In this method, add these five lines:

SPListItem item = workflowProperties.Item;
SPListItem task =
workflowProperties.TaskList.GetItemById(taskProperties.TaskItemId);
item["GradingScore"] = task["GradingScore"];
item["GradingNotes"] = task["GradingNotes"];
item.SystemUpdate(false);

These five lines get the item for which the workflow was started, the task that was created, and then copy two fields from the task into the item. Finally, the code performs a system update to update the fields without changing the modified information for the item.

Completing the Delete Task Activity

Completing the Delete Task activity is the same as completing the OnTaskChanged activity. You must set the CorrelationToken and the TaskId properties of the deleteTask1 activity so that the workflow will compile, and so that the task will be deleted. You can refer to the earlier section, "Completing OnTaskChanged," for the steps to bind these two properties.

The workflow is done. It should now build successfully. It's time to move on to deploying the workflow.

Modifying the Feature to Deploy the Workflow

When VS created the project, it automatically added the following three files that will help in the deployment process:

  • Feature.xml — This file is a Feature file that SharePoint needs to define the Feature.

  • Workflow.xml — This is an element manifest file that defines the workflow itself.

  • Install.bat — This is a batch file that can be used to install the Feature.

The following sections walk you through the creation of each of these files, and making the updates necessary to install the Feature containing the Grades workflow.

feature.xml

Upon opening feature.xml, you'll notice that there isn't much there besides a note telling you to use the snippets functionality with VS to add the nodes necessary in the feature.xml file. To create the feature.xml for the Grades workflow, follow these steps:

  1. Add the feature from the WSS SDK by right-clicking, selecting Insert Snippet

    feature.xml

    Note

    If, for some reason, you don't see the Windows SharePoint Services Workflow snippets when you try to insert the snippets, you can manually add them by opening the Code Snippet Manager (Tools

    feature.xml
    Feature.xml with the inserted snippet

    Figure 8.5. Feature.xml with the inserted snippet

  2. Select Tools

    Feature.xml with the inserted snippet
  3. Verify that the Create GUID application has the radio button for "4. Registry Format (ie. {xxxxxxxx-xxxx ... xxxx })" selected.

  4. Click the Copy button in the Create GUID application.

  5. Switch back to Visual Studio and the feature.xml file.

  6. Select the text in the quotes behind the Id attribute and paste in the GUID using the Ctrl+V key sequence.

  7. Strip the leading and closing braces from the GUID that was pasted in.

  8. Enter a descriptive name for the Feature and for the description. For the Grades workflow, the Feature is going to be called "Grades" and the description is "Enable assignment grading."

Because workflow.xml is the correct name of the element manifest that you want to create, you are finished with feature.xml. Save it and let's move on to workflow.xml.

workflow.xml

When workflow.xml is opened, you'll find the situation very similar to the feature.xml. workflow.xml is a mostly empty file with a few instructions on how to add the content to the file. Let's follow a similar procedure as you did with the feature.xml file. To customize workflow.xml for the Grades workflow, follow these steps:

  1. Right-click and select Insert Snippet

    workflow.xml
  2. The next step is entering the name and description for the workflow. For the Grades workflow, use "Grades" and "Enable assignment grading," respectively, for the name and description. It isn't required that you enter either the same or unique names in here versus the values that are used in the feature.xml file.

    workflow.xml with snippet

    Figure 8.6. workflow.xml with snippet

  3. Use the Create GUID tool to create a new GUID. (See Steps 2–4 of the feature.xml procedure if you don't remember how.)

  4. Switch back to VS and the workflow.xml file.

  5. Paste the GUID into the ID attribute's value and delete the extra braces.

  6. The next step is the code-behind class. In this case, the project name is "Grades," so the namespace is Grades. For the CodeBesideClass, enter Grades.Workflow1. Workflow1 is the name of the workflow that was created by the Visual Studio SharePoint Sequential Workflow project.

  7. Next, you must get the correct assembly name. The first part of the CodeBesideAssembly is ProjectName. This is the name of the DLL for the project. In this case, Grades, so replace ProjectName with Grades.

  8. The last part of the CodeBesideAssembly is the PublicKeyToken. For this, the assembly must be strong-named. This is a requirement for all workflow DLLs because they must be installed into the Global Assembly Cache (GAC). In VS, right-click the project name (Grades) and select Properties. On the properties page that appears, select the Signing tab (the last tab on the left). The result will be similar to the page shown in Figure 8-7.

    The Signing tab of the project properties page

    Figure 8.7. The Signing tab of the project properties page

  9. Drop down the "Choose a strong name key file" drop-down box and select New. A Create Strong Name Key dialog will appear.

  10. Enter a key file name of Grades.

  11. Uncheck the "Protect my key file with a password" checkbox and click the OK button.

  12. To get the public key token, you'll need to build the solution, so build the solution now. (Use the key sequence Ctrl+Shift+B to build the solution.)

  13. Next, open a VS 2005 command prompt. This can be done by selecting it from the Start menu. The entry is located under Visual Studio 2005

    The Signing tab of the project properties page
  14. Navigate to the directory where the project DLL is created. In this example, I created the solution in C:WorkMVPBookgrades. The debug DLL is created under bindebug by default, so the command to change to the correct directory is CD workMVPBookgradesindebug to change to that directory.

  15. Type the command SN —T Grades.DLL. The response to this command shows the public key token for the file, as shown in Figure 8-8.

    Public key token

    Figure 8.8. Public key token

  16. Right-click in the window and select Mark.

  17. Click and drag across the public key token. When you're finished, release the mouse and press Enter.

  18. Switch back to VS and to the workflow.xml tab.

  19. Select the green highlighted publicKeyToken and then press Ctrl+V to paste the key.

  20. One final edit for the CodeBesideAssembly attribute is to change the version number from 1.0.0.0 to 3.0.0.0.

  21. Next, set the TaskListContentTypeId. This is the Id shown in the content type section. In this case, the value was the 0x01080100B7336179CFFE43e59B86E241C767010E value from the content type tag that defined the content type for the task.

  22. Delete the AssociationUrl, InstantiationUrl, ModificationUrl, and StatusUrl attributes, because the Grades project doesn't implement any of these Features.

  23. Delete the whole MetaData node and the modification element under it because the Grades workflow doesn't implement a workflow modification either.

  24. If you were just doing the workflow in this file, you would be finished. However, let's simplify things a bit and add our fields and content types to the top of this file. So, copy the field and content type nodes above the <Workflow> node you've been modifying. Figure 8-9 shows what the completed file should look like. Note that the formatting was changed and extraneous comments removed to get everything to fit on the screen.

    The content type fragment of the completed workflow.xml

    Figure 8.9. The content type fragment of the completed workflow.xml

With workflow.xml finished, there's only one more file to finish: the install.bat file.

install.bat

When you double-click it in the Solution Explorer, the install.bat file opens to reveal quite a few commands and instructions. It's a nice change from the feature.xml and workflow.xml files that you saw before. The changes you need to make to the install.bat file are basically two global searches and replaces. To customize the install.bat file, follow these steps:

  1. The first step is to search for MyFeature and replace it with what you want to name your Feature — in this case, Grades. To perform the search and replace, start by pressing Ctrl+H.

  2. Enter MyFeature in the "Find what" box and Grades in the "Replace with" box. Make sure that the "Look in" drop-down list is set to Current Document. Click the Replace All button.

  3. Click OK in the message box indicating 14 replacements were made.

  4. The next step is to search for http://localhost and replace it with the name of your server. In my case, the server name is w2k3server, so I'm replacing http://localhost with http://w2k3server.

  5. Click the OK button in the message box indicating three replacements were made.

Once you've made all of the replacements, select Save All in Visual Studio (File

install.bat

Associating the Workflow to a Document Library

Now that the workflow and associated content types are created, it's time to associate those content types and the workflow to a set of lists in SharePoint. For these instructions, you'll need a blank team site. I've created one called Grades under the root of my server. You can use the root site of your installation, or create a site underneath the root site to associate the content types and workflow.

To associate the content type for the grading document (which has the score and notes field) to the document library and remove the default content type, follow these steps:

  1. Open up the document library and then, from the Settings menu, select the Document Library Settings entry.

  2. The first step is to activate the content type. You do that by clicking the Advanced Settings in the General Settings section. The top item on the Document Library Advanced Settings page is "Allow management of content types." Select the Yes radio button and scroll down to the bottom of the page and click the OK button.

  3. Back on the Customize Shared Documents page, in the Content Types section, click "Add from existing site content types."

  4. On the Add Content Types page in the "Select site content types from:" drop-down list, select Grading. Click the Add button to move the GradingDocument to the "Content types to add:" box. Click the OK button to finish.

  5. The next step is to remove the Document type so that all documents that are created in the document library will be the GradingDocument type. Click on the Document link under the Content Types heading.

  6. From the List Content Type page, click the "Delete this content type" link.

  7. Click the OK button on the popup dialog that asks if you're sure.

With the content type in place, it's time to associate the workflow. That can be done by following these steps:

  1. From the Customize Shared Documents page, in the Permissions and Management column, click the Workflow Settings link.

  2. On the Add a Workflow page in the "Select a workflow template:" list box, scroll down and select the Grades workflow template.

  3. Enter a name for this workflow association, Grades.

  4. Scroll down to the Start Options section and check "Start this workflow when a new item is created" checkbox. Click the OK button. The grades workflow is added to the document library.

All of the plumbing is done. All that is left is to test the workflow and ensure that it works.

Testing the Workflow

Now that the workflow is associated with a document library and set to activate on new items, all that needs to happen is that a document be uploaded. When this happens, the Grades workflow will kick off and add a new task to the workflow. Figure 8-10 shows the task created when the feature.xml file from the Grades project was uploaded to the Shared Documents library.

The new task created by the Grades workflow

Figure 8.10. The new task created by the Grades workflow

If you update the task to include a score and notes, you'll notice that the task doesn't always go away immediately. Sometimes when you first refresh the task list, the task will appear, and sometimes it won't. Because the workflow and the refresh of the task list page occur at the same time, it's possible you'll see or not see the task, depending upon which thread executed quicker. Refreshing the task list page will definitely make the task disappear.

Switching back to the Shared Documents list, you'll see that there is a column called Grades — which matches the association name you provided when you associated the workflow with the list — and that it has a value of Completed. Figure 8-11 shows the completed Grades workflow.

Completed Grades workflow

Figure 8.11. Completed Grades workflow

The properties of the document were, in fact, updated, based on what was entered in the task. Figure 8-12 shows that the student got a score of 100 and a note of Good Work!

The results of the Grades workflow

Figure 8.12. The results of the Grades workflow

Debugging Workflows

Without a doubt, you're going to need to debug your workflow. With the scant documentation, and the odd little quirks, there are going to be issues that are unanticipated. In this section, you learn some debugging techniques that you can use with SharePoint to find defects quicker and with less pain.

Fault Handlers

One of the key techniques for making the workflow debugging process easier is to add a fault handler to your workflow that logs the exception that caused the error to the history log for the workflow. This gives you a way to capture exceptions in your code wherever they occur.

Not all exceptions are caught by the fault handler. Some exceptions are so core to the workflow that they are only caught in the ULS log. The fault handler is a great way to capture errors in your code that don't relate to core workflow operations.

Adding a fault handler isn't that complicated. To demonstrate how easy it is, the following procedure shows how to add a fault handler to the Grades workflow created earlier:

  1. Open the Workflow1.cs [Design] page in VS by double-clicking Workflow1.cs in the Solution Explorer.

  2. Right-click in the white space to the left or right of the workflow activities and select View Fault Handlers.

  3. Drag the FaultHandler activity from the toolbox into the horizontal area under the faultHandlersActivity1, as shown in Figure 8-13.

  4. Right-click the faultHandlerActivity1 that you just created and select Properties from the context menu.

    Adding a fault handler

    Figure 8.13. Adding a fault handler

  5. Click the FaultType property and then the ellipsis button.

  6. Enter System.Exception in the Type Name box and press Enter. In .NET, all exceptions derive from System.Exception, thus this type will be a part of all exceptions and will be caught by this fault handler.

  7. Drag the LogToHistoryListActivity into the main area of the workflow surface where it says Drop Activities Here.

  8. Right-click the LogToHistoryListActivity1 that you just dragged into the design surface and select Generate Handlers from the context menu.

  9. Add the following code to the logToHistoryListActivity1_MethodInvoking method:

    LogToHistoryListActivity log = (LogToHistoryListActivity)sender;
    log.HistoryDescription = faultHandlerActivity1.Fault.ToString();
    log.OtherData = faultHandlerActivity1.Fault.ToString();

    This code places a string representation of the exception into HistoryDescription and into the OtherData field. This is because HistoryDescription is visible in the workflow history, but is limited to 255 characters. OtherData doesn't have a limit, but is only visible by navigating to the hidden HistoryList table.

  10. Switch back to Workflow1.cs [Design].

  11. Right-click the white space to the left or right of the fault handler and select "View SharePointSequentialWorkflowActivity" from the context menu.

With the fault handler in place, you can create an intentional error in the Grades workflow to cause the fault handler to execute. When I changed the codeActivity1_Execute code to the code in the following box, and ran the workflow again, the workflow history showed the Null Reference Exception, as seen in Figure 8-14.

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    SPListItem item = workflowProperties.Item;
    SPListItem task = null;/* =
    workflowProperties.TaskList.GetItemById(taskProperties.TaskItemId);
    */
    item["GradingScore"] = task["GradingScore"];
    item["GradingNotes"] = task["GradingNotes"];
    item.SystemUpdate(false);
}

That's a great start on the exception, but in reality, the entire text of the exception didn't fit. To see the entire text of the exception, including the full call stack, you'll need to view the Workflow History list directly. The Workflow History list was created as a hidden list, so you won't find it by navigating the user interface. However, you can directly enter the URL by appending Lists/Workflow%20History to the end of the site name. Thus, if the site name is http://w2k3server/grades, the full URL is http://w2k3server/grades/Lists/Workflow%20History. Figure 8-15 shows the extra data that you stored into OtherData — that wasn't displayed in the Description field.

The fault handler logged the exception

Figure 8.14. The fault handler logged the exception

The Description and OtherData columns of the History list, respectively

Figure 8.15. The Description and OtherData columns of the History list, respectively

Logging Messages

Perhaps logging messages isn't the most glamorous way to debug something — but it's effective. Ever since the first programmers started adding PRINT statements to their code to dump out important variables at key times, we've been using the PRINT statement (or its updated equivalent) to gain insight to the inner workings of the code we write. SharePoint is no different. The PRINT statement in SharePoint workflow land is a LogToHistoryList activity. You've already seen it in use in the fault handler. You can just as easily add it to the mainline part of the workflow to drop yourself notes about where the workflow is — and what the values of key variables are.

Breakpoints and Attaching to a Process

Interactive debugging has made the need for logging statements nearly obsolete for most technology platforms. Though you can use interactive debugging with SharePoint, the process is still somewhat painful and, in some cases, inserting LogToHistoryList activities may be a simpler way to understand what is going on with your workflow.

Interactive debugging with SharePoint and workflows must be done by attaching to the IIS worker process (W3WP). Once attached to the process, you can set breakpoints, step through code, and inspect variables, with the following caveats:

  • First chance exceptions — Interactive debugging offers the capability of receiving an exception before the code gets it. This is useful when you want to run the interactive debugger at full speed until a problem occurs, and then stop and tear it apart. Although you can turn on first chance exceptions in VS, they won't be caught while debugging SharePoint workflows.

  • Processor utilization — If you use the workflow debugging template (explained later in this chapter), your machine's processor will go to and stay at 100 percent utilization the entire debugging session. This normally isn't a problem, except that some internals of .NET (the garbage collector) will not run when the system is under a 100 percent load, until it's out of memory.

  • Step carefully — If you attempt to step over an activity that causes a serialization (dehydration) and deserialization (rehydration) event, the code will resume running at full speed. This makes sense, because the execution context ends and a new one is created when the triggering event occurs. However, it makes stepping through a workflow challenging at times.

  • Sometimes breakpoints — Breakpoints don't always fire. This is particularly true for activities immediately following serialization/deserialization events.

Other than these caveats, debugging SharePoint workflows in VS isn't much different than debugging managed code. The Visual Studio Extensions for .NET 3.0 (Windows WF) does add a new code type that you can attach to — Workflow — as shown in Figure 8-16. By selecting this code type for debugging, you can set breakpoints on the activities in a workflow. Unlike other code types, the Workflow code type is mutually exclusive with the Managed code type. This isn't a problem in practice, however, because the Workflow code type allows you to debug managed code as well.

The Workflow code type to debug workflows

Figure 8.16. The Workflow code type to debug workflows

Common Exceptions

Knowing what the status codes, exceptions, and messages in the log file typically mean can certainly be enlightening on the problems. As mentioned earlier, the SharePoint log files, called Universal Logging Service (ULS) files, are located in C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions12LOGS. They are the primary place that SharePoint will log internal exceptions to — particularly the workflow area of the product.

Table 8-1 shows a set of workflow statuses, messages, and resolutions that may help you locate your problem.

Table 8.1. Workflow Statuses, Messages, and Resolutions

Workflow Status

Exception / ULS Log Entry

Problem and Resolution

Failed on Start

[ULS] Load Workflow Assembly: System.IO .FileNotFoundException: Could not load file or assembly...

SharePoint cannot locate the workflow assembly that you've listed in the <Workflow> node in your elements XML. Correct the entry or GAC the assembly.

Error Occurred

[ULS] Unexpected System.Reflection .TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.SharePoint.Workflow.SPWinOETaskService .CreateTaskWithContentTypeInternal(Guid taskId, SPWorkflowTaskProperties properties, Boolean useDefaultContentType, SPContentTypeId ctid, HybridDictionary specialPermissions) at Microsoft.SharePoint.Workflow.SPWinOETaskService .CreateTask(Guid taskId, SPWorkflowTaskProperties properties, HybridDictionary specialPermissions)

You added a CreateTask activity to the workflow, but didn't initialize the taskId or taskProperties properly. Create a new instance of SPWorkflowTaskProperties and bind it to the TaskProperties property of the CreateTask activity. Create new taskId GUID and initialize it to a new GUID in the MethodInvoking event or before.

Error Occurred

[Exception] System.NullReferenceException: Object reference not set to an instance of an object

When using the CreateTaskWithContentType activity on a task list that doesn't have content types enabled, set the .ContentTypesEnabled = true and add the content type referenced in CreateTaskWithContentType.

Error Occurred

[Exception] SPException: This task is currently locked by a running workflow and connot be edited.

Tasks for a SharePoint workflow can only be modified by the user while in an OnTaskChanged activity and by the workflow itself within an UpdateTaskActivity. When updating the task in an UpdateTaskActivity, it must be updated through the SPWorkflowTaskProperties object.

Error Occurred

[Exception] Microsoft.SharePoint.SPException: The security validation for this page is invalid.

SPWorkflowManager .StartWorkflow() cannot be called from a HTTP GET — it must be called from an HTTP POST. Setting the SPWeb.AllowUnsafeUpdates won't help.

Error Occurred

[ULS] System.InvalidOperationException: The event receiver context for Workflow is invalid.

For the CreateTaskActivity, the taskID must be set to a unique GUID and the TaskProperties must be set to a SPWorkflowTaskProperties object.

Summary

When you put together all the pieces presented in this chapter, you have a powerful array of workflow options, including a nearly limitless platform for custom workflow development. The simple workflow created in this chapter shows the power of being able to control the fields that are used in the workflow and, more importantly, a method that users can interact with the workflow to change or add data once it's running. Couple that with debugging techniques and common problems discussed here, and you're ready to develop workflows with WSS.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.236.187