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).
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.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
To create the outline for the Grades workflow, follow these steps:
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.
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.
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.
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:
Click the createTask1
activity, then right-click and select Properties.
In the Properties pane, select the CorrelationToken
box, type in taskToken, and press Enter.
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.
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();
Switch back to the Design view, which appears in the tabs as Workflow1.cs [Design].
Click the createTask1
activity, right-click, and select Properties from the context menu.
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.
Select the taskId
property and click the OK button. You've just bound the taskId
property to the taskId
that you created.
Perform Steps 7 and 8 again on the TaskProperties
activity property and taskProperties
workflow property.
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();
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;
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.)
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.
Select the onTaskChanged1
activity, right-click, and select Properties from the context menu.
In the CorrelationToken
field, click the drop-down list box arrow and select taskToken
.
Click the TaskId
property field and then the ellipsis.
Select taskId
from the binding dialog and click the OK button.
Select the AfterProperties
field and click the ellipsis.
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.
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 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.
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.
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:
Add the feature from the WSS SDK by right-clicking, selecting Insert Snippet
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
Select Tools
Verify that the Create GUID application has the radio button for "4. Registry Format (ie. {xxxxxxxx-xxxx ... xxxx })" selected.
Click the Copy button in the Create GUID application.
Switch back to Visual Studio and the feature.xml
file.
Select the text in the quotes behind the Id
attribute and paste in the GUID using the Ctrl+V key sequence.
Strip the leading and closing braces from the GUID that was pasted in.
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
.
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:
Right-click and select Insert Snippet
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.
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.)
Switch back to VS and the workflow.xml
file.
Paste the GUID into the ID
attribute's value and delete the extra braces.
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.
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
.
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.
Drop down the "Choose a strong name key file" drop-down box and select New. A Create Strong Name Key dialog will appear.
Enter a key file name of Grades.
Uncheck the "Protect my key file with a password" checkbox and click the OK button.
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.)
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
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.
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.
Right-click in the window and select Mark.
Click and drag across the public key token. When you're finished, release the mouse and press Enter.
Switch back to VS and to the workflow.xml tab.
Select the green highlighted publicKeyToken
and then press Ctrl+V to paste the key.
One final edit for the CodeBesideAssembly
attribute is to change the version number from 1.0.0.0
to 3.0.0.0
.
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.
Delete the AssociationUrl
, InstantiationUrl
, ModificationUrl
, and StatusUrl
attributes, because the Grades project doesn't implement any of these Features.
Delete the whole MetaData
node and the modification element under it because the Grades workflow doesn't implement a workflow modification either.
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.
With workflow.xml
finished, there's only one more file to finish: the install.bat
file.
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:
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.
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.
Click OK in the message box indicating 14 replacements were made.
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
.
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
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:
Open up the document library and then, from the Settings menu, select the Document Library Settings entry.
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.
Back on the Customize Shared Documents page, in the Content Types section, click "Add from existing site content types."
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.
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.
From the List Content Type page, click the "Delete this content type" link.
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:
From the Customize Shared Documents page, in the Permissions and Management column, click the Workflow Settings link.
On the Add a Workflow page in the "Select a workflow template:" list box, scroll down and select the Grades workflow template.
Enter a name for this workflow association, Grades.
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.
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.
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.
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!
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.
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:
Open the Workflow1.cs [Design] page in VS by double-clicking Workflow1.cs
in the Solution Explorer.
Right-click in the white space to the left or right of the workflow activities and select View Fault Handlers.
Drag the FaultHandler
activity from the toolbox into the horizontal area under the faultHandlersActivity1
, as shown in Figure 8-13.
Right-click the faultHandlerActivity1
that you just created and select Properties from the context menu.
Click the FaultType
property and then the ellipsis button.
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.
Drag the LogToHistoryListActivity
into the main area of the workflow surface where it says Drop Activities Here.
Right-click the LogToHistoryListActivity1
that you just dragged into the design surface and select Generate Handlers from the context menu.
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.
Switch back to Workflow1.cs [Design].
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.
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.
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.
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 |
| SharePoint cannot locate the workflow assembly that you've listed in the |
Error Occurred |
| You added a |
Error Occurred |
| When using the |
Error Occurred |
| Tasks for a SharePoint workflow can only be modified by the user while in an |
Error Occurred |
|
|
Error Occurred |
| For the |
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.
3.149.236.187