Building and Distributing Workflows in SharePoint Products and Technologies for Use in Customer and Partner Environments

Summary: Learn about the steps that are necessary to successfully deliver a workflow into a customer or partner environment using SharePoint Products and Technologies. (24 printed pages)

David Mann

June 2008

Applies to: Windows SharePoint Services 3.0, Microsoft Office SharePoint Server 2007, Microsoft Visual Studio 2008

Download the sample code for this article.

Contents

  • Overview of Workflows in Customer and Partner Environments

  • Planning and Designing for Multi-Environment Deployment

  • Defensive Coding

  • Supporting Customizations

  • When Things Go Wrong

  • Logging

  • Deployment

  • Documenting Your Workflow

  • Summary

  • Additional Resources

Overview of Workflows in Customer and Partner Environments

Writing and supporting software that is intended to run in a customer’s or partner’s environment can be a somewhat scary prospect. Lack of control, disparate environment specifications, unknown end users, and lack of direct interaction are just a few of the potential issues that you must deal with. For independent software vendors, or ISVs, these issues are a fact of life. This is just one more item to be concerned about when they introduce workflow into their application.

This article does not deal directly with the basic process of building and deploying a workflow. Instead, it focuses on the extra steps necessary to successfully deliver a workflow into a customer or partner environment.

The goal of this article is to make you think about workflows differently: to think about them as part of your product or application—not as an afterthought. I’ll raise many issues, give you a lot to think about, and point out some (not all) possible paths to a solution. The final direction you take depends on your application, your company, and your clients. It is likely that not all of the points made in this article will apply to your situation, and that is fine; just make it a conscious decision to disregard them—don’t just ignore them.

Planning and Designing for Multi-Environment Deployment

Before writing any code, you must thoroughly plan and design a workflow that is destined for external deployment—more so than in an in-house scenario. The simple fact that you have less knowledge of, and less control over, the environment within which your workflows may have to operate means that your up-front planning must be more deliberate and more thorough.

There are several elements to this—starting with identifying which version of Microsoft SharePoint Products and Technologies must be in place before your workflow can even run. You will revisit this information more than once during the development life cycle to keep it current, but this is the point at which you can lay the foundation.

Identifying the Development Tools

It may seem a little strange to start with choosing your development tool. Surely, it is more important to understand your requirements before you select a tool? Usually, yes, this would be the case. However, for SharePoint workflows, we flip things around a bit; with good reason, as you will soon see.

As you probably already know, there are two tools available for creating workflows in the 2007 Microsoft Office system—Microsoft Visual Studio and Microsoft Office SharePoint Designer. The question is, which of these will you use to develop your workflow? Before you think too much about this, here is some good news: this is a trick question. This is not a decision that you have to make. There is not really a viable means of deploying Office SharePoint Designer workflows that enables you to package your workflow for distribution, so this really is not an option for us in this case. You have no choice but to use Visual Studio to develop the workflow.

Because of this, the rest of this article focuses entirely on Visual Studio workflows.

Identifying the Environment

This is your opportunity to define the most basic requirements that must be met for your workflow to be supported. Naturally, for SharePoint workflows, you must have SharePoint Products and Technologies. But the question is, which version do you need? Will your workflow require anything that is available only in Microsoft Office SharePoint Server, or will the base-level Windows SharePoint Services 3.0 be sufficient? If Office SharePoint Server is required, do you need Enterprise or Standard?

Keeping with the theme of making your workflow available as widely as possible, unless you know right from the beginning that your workflow needs something available only in Office SharePoint Server, you should start by targeting Windows SharePoint Services only. This means that your development and testing environment should have only Windows SharePoint Services installed—not Office SharePoint Server. For a great breakdown of what is available in the different versions of SharePoint Products and Technologies that might help make this decision, see Microsoft Office SharePoint Server 2007 products comparison download.

One difference between Office SharePoint Server and Windows SharePoint Services that you should not consider here is InfoPath Forms Services. This component is available in Office SharePoint Server but not in Windows SharePoint Services. There are two reasons to ignore this component for now:

  1. The functionality provided by Forms Services, that is, rendering workflow forms in the browser, is available without it. The difference is that you manually create the ASPX forms instead of creating the form in Microsoft Office InfoPath (a richer forms development environment) and letting the Forms Server convert it to HTML/ASPX for you. This requires more work to build your forms because you must build and integrate the ASPX forms by hand, but it is not overly difficult.

  2. If you absolutely must develop your forms in InfoPath and have them converted for you (although I cannot imagine why this would be the case, I certainly do not presume to know all of your business requirements), you can still avoid requiring Office SharePoint Server by simply requiring Forms Server, a separate release within the SharePoint Products and Technologies family. Although this is more than simply Windows SharePoint Services, it is still less onerous (and costly) than the full version of Office SharePoint Server.

    NoteNote

    Like every good rule, this one also has an exception. If a your application requires that your workflow forms be rendered directly into the 2007 Office system programs, you will need Office SharePoint Server, because that is the only way to have the Web services and components that are necessary for this level of integration. Windows SharePoint Services and Forms Server do not provide this functionality.

Unless otherwise noted, the rest of this article assumes that you are developing your workflow by targeting Windows SharePoint Services without Forms Server.

Workflow Paradigm

Windows Workflow Foundation (WF), the foundation upon which SharePoint workflows are built, supports two types of workflows out of the box: sequential and state machine. Although no one outside your development team will likely ever know which approach you choose, it is nonetheless a far-reaching decision, important enough to spend a little time understanding the difference between the two.

Sequential Workflows

Perhaps the best way to describe a sequential workflow is as a flowchart. Sequential workflows have a beginning, an ending, and a fairly clearly defined path between the two. Although they can support multiple levels of branching and conditional logic, sequential workflows tend to become confusing and unwieldy when they grow overly involved. Sequential workflows are also potentially more difficult to maintain and extend once they are defined and built.

Figure 1 shows an example of a simple sequential workflow. Without too much effort, you can trace the logic that is defined by the workflow.

Figure 1. A simple sequential workflow

A simple sequential workflow

Sequential workflows are best used in support of highly structured processes. They imply a straightforward path that has few conditional execution elements and that will not change much in the future. As you will see shortly, it is also somewhat more difficult to write bulletproof sequential workflows.

State Machine Workflows

State machine workflows are entirely different from sequential workflows. Made up of a collection of conditions (known as “states,” hence the name of the paradigm), the transitions between those conditions, and the events that trigger those transitions, state machines excel at defining complex processes. Figure 2 shows an example of a simple state machine workflow.

Figure 2. A simple state machine workflow

A simple state machine workflow

You can see from Figure 2 that there is no type of defined path through the process. Instead, the path is entirely dependent upon the events that occur.

Hidden within each state of the workflow is the secret to a state machine’s power. If you double-click the StateInitialization, EventDrivenActivity, or StateFinalization activities within a state, you see the regular sequential workflow designer, as shown in Figure 3. In a sense, then, a state machine workflow is made up of multiple associated sequential workflows.

Figure 3. Hidden inside each state in the state machine is a series of regular sequential workflows

Sequential workflows hidden inside each state

This is what makes this approach so powerful. Each state in a state machine can have multiple related processes. Two of them—StateInitialization and StateFinalization—always process, when the state is entered or exited, respectively. The third is in the EventDrivenActivity. It executes when the event associated with the state occurs.

Workflow Paradigm Summary

With an understanding of the two approaches available, we can now examine the best approach to take to meet our goals. On the one hand, it is important to understand that there really is no clear answer here; either option will work. On the other hand, some features of state machines (particularly their simplified support for branching and conditional logic) make them better suited to writing the highly controlled, highly reliable workflows that we want. Naturally, that affinity comes at a price. State machines are harder to become accustomed to; many developers find this approach harder to adopt than a simple flowchart.

In addition to this, there are a number of other important factors to consider. To choose the best approach for your particular situation, you also need to answer a few questions:

  • How stable is your product? If the product itself is new, and it is growing and adapting rapidly as it continues to evolve based on market conditions and demands, you probably have a more volatile environment. Keep this in mind as you answer the next question.

  • What is the volatility of the process being modeled? If it is likely to change frequently, you should choose a state machine because it will be easier to maintain.

  • What is the complexity of the process being modeled? Do you have to support multiple execution paths with conditional logic, looping, and branching? If so, then again, state machines support this complexity more easily. However, if your process consists primarily of single-path processing, sequential may be a better option. You certainly need a good understanding of your business process in order to answer this question completely.

  • What is the skill level and workload of your development staff? State machines are typically more complicated to build and often require more development discipline. If this does not fit your development environment, perhaps you want to avoid this complexity. The difficulty in answering this question accurately stems from the fact that the workflow you are building may exist at client locations for many years and outlive more than one development staff. Instead of thinking about specific individuals currently on staff, instead think about the general type of individual your organization tends to hire and the typical workload.

  • Do you need to dynamically create tasks and assign them based upon criteria known only at run time? If so, you must use a sequential workflow because the Replicator activity cannot operate correctly in a state machine workflow.

Answers to those questions will help you decide which type of workflow to support—sequential or state machine. Understand, too, that these options are not mutually exclusive. You could support a sequential workflow for one process and a state machine workflow for another process all within the same application. Choose the one that best fits each process that you must support.

I will close this section by making the following recommendation: unless you have a compelling reason to build a sequential workflow, the best approach is likely to be a state machine workflow.

Workflow User Interfaces

The user interface for SharePoint workflows is delivered entirely through forms. We can create them manually or let InfoPath Forms Server create them for us. As mentioned earlier, there are significant implications for the environment required for your workflow based on this decision. We’ll cover each option here.

Whichever option you choose (InfoPath or ASPX), you can provide four forms as part of your workflow:

  • Association   Used for making a workflow template available on a specific list or library. Users can then create instances of that template connected to a specific document or list item.

  • Initiation   Used for creating an instance of a workflow template on a specific document or list item.

  • Task   A central part of most SharePoint workflows is the act of assigning work items to users. This form lets you customize the experience and the capabilities exposed by the Task form.

  • Modification   Facilitates an advanced capability of SharePoint workflows, that is, the ability to change a workflow while it is running (for example, changing task assignments, changing processing instructions, and so on).

InfoPath Forms

Although the result of either form-development approach is almost identical, InfoPath forms are easier to develop. Part of this is because the InfoPath client application is a very rich form development tool. Part of it is because the SharePoint Products and Technologies product team enhanced the interaction capabilities between InfoPath forms and the workflow host. As you will see, this is the benefit of using InfoPath forms.

A detailed review of the process for building an InfoPath form for use in a workflow is beyond the scope of this article. For more information, see Additional Resources in this article.

ASPX Forms

Although all workflow forms are ultimately delivered through an ASPX page, the difference here is that in this case, you must build the form manually in Visual Studio. Although this is not a difficult task, it is still more difficult than an InfoPath form. The hard part lies largely in the back-end form processing. The front end is simply building an ASPX form, which is not very difficult or different from any other ASPX form you have ever built. As with the InfoPath forms, a detailed description of the process is beyond the scope of this article.

Workflow Security

Security in SharePoint workflows is a double-edged sword. On one side, it is a non-event. All Visual Studio workflows run as the System Account so that the workflow can do whatever it needs to: reading and writing lists and libraries, manipulating content and structure, and so on. You do not have to worry about permissions or impersonation. On the other hand, all workflows run as the System Account and can do anything. This is a problem if it exposes functionality that you do not want your users to have.

NoteNote

Even though this article focuses on Visual Studio workflows, it is worth pointing out an important difference between Visual Studio workflows and SharePoint Designer workflows. As mentioned above, all Visual Studio workflows run as the System Account and have full rights to everything in SharePoint Products and Technologies. SharePoint Designer workflows, on the other hand, still run as the System Account, but they do so with their permissions trimmed down to those of the account that initiates the workflow. You should keep this important distinction in mind.

From a design perspective, you must think about both sides of this to make sure that your needs are met and, more important, that you do not unintentionally expose your customer’s or partner’s system to a security vulnerability. To manage this part of the design correctly, you must look at your workflow from a security perspective after you map out the process itself.

Look for areas in which you are reading from, or writing to, your core application—either through Web services or through an object model API. Look for places where you are accepting user input, and make sure that you properly analyze and encode it before you interact with it, process it, or store it.

Also, you must consider the fact that for your workflow to run in the customer environment, any custom activities that you build must be installed on the customer’s server. There is nothing to prevent a customer from using one of those activities in a workflow of their own. Does this present a problem? Are your activities an exposure point that could give a customer access to information from your application that they should not have? Carefully consider what properties you expose on your custom activities to make sure that they have to be exposed, and ensure that they cannot be used in a way that was not intended by your design.

This security review is no different from a regular vulnerability assessment that you would do on any other part of your application. The important thing is to make sure that your workflow processes are included in the security assessment, especially since the workflow will run as the System Account.

Workflow Error Handling

Error handling is largely an implementation activity, but from a design and planning perspective, it is important to spend some time thinking about it. What areas of your process are most likely to present the potential for error? How will you handle errors when you catch them? How will you test various scenarios to ensure that your error handling is adequate? You should address these and other questions in your planning so that you have the answers readily available when it comes time to begin development.

In development, you must include error handling as part of the standard development process—not as a piece that is added later. Again, like many things here, this is not something unique to workflows running in an external environment. However, it is as important to have proper error handling in what may be considered an auxiliary process as it is in your main application. Think about errors, talk about errors, plan for errors and you’ll be more ready to handle errors.

One final element to think about regarding workflow error handling is that the final piece of error handling is completely out of your control. In SharePoint Products and Technologies, like any ASP.NET application, the final configuration of error handling is done in the Web.config file for the Web application. Your application cannot assume that the Web.config file is set up correctly. Other applications or inexperienced administrators could easily change the settings in Web.config and expose pieces of your application to scrutiny that you would rather not have. If for no other reason, this reason is enough to warrant the extra time required to do correct error handling.

For more information about how to do error handling in workflows, see the Error Handling_ and Cancellation Handling sections in this article.

Workflow Dependencies

Finally, with all of the above out of the way, it is time to look at the dependencies that your workflow might have. Do you need to have a certain list available? Does it need to be at a predefined URL? Do you need a connection string from Web.config? How about configuration information from a list or some other source?

As part of your design and planning, you must list these dependencies, the implications of them not being available, and possible courses of action if they are not. Error handling is driven, in part, by this list. But more important, it touches upon your strategy and standards for defensive coding and your plan for making your process self healing.

For now, just examine your process and list every dependency, no matter how small. Later, this article covers some defensive coding strategies for dealing with unmet dependency situations and some approaches for preventing problems from occurring in the first place.

Planning and Designing Summary

While the preceding discussions are not unique to the process of planning a workflow targeted towards an external environment, they are the ones that are important to nail right away. A mistake here in any development process is problematic. In a workflow to be run in an external environment, they can be disastrous.

The rest of your design and planning process is going to be largely uneventful, no different from any other workflow. You need to think about all of the items that are unique to your process and your application. Completely map out your processes; know what will happen at every decision point or at every event transition

With all of that said, there is one more important decision item to take care of. It is during this step of the process that your organization must make a difficult decision. After the initial design is complete, you must make a preliminary decision whether or not to continue. If your initial list of requirements is too cumbersome and unrealistic, and your design is too complex to be readily developed and supported for the lifetime of your product, perhaps it is unwise to continue. We will cover ways to avoid this throughout this article, but if it is the case, an alternative may be to deliver functionality in the form of modular workflow components and let your customers or partners develop their own full workflows.

Defensive Coding

There are few places where practicing good defensive coding is more important than in a collaborative application running in an environment over which you have no control. Any number of things could happen after your workflow is installed and activated that would render it totally, or perhaps worse, partially non-functional. Potentially dozens if not hundreds of people have the ability to break your workflow, either maliciously or accidently, and you can do little to stop them. For this reason, your workflow needs to be cautious, non-trusting, and as much as possible, self-healing.

We’ll cover some techniques for dealing with this potential problem in the following sections. As with many other things in this article, some of these elements are not unique to workflow development. They are simply good programming practices. The twist added by workflow is that you are working in a highly visual environment. It may not occur to you to think along these lines because a large part of what you’re doing does not involve writing code—it is simply configuring pre-built activities.

Verify Before Use

What happens to a workflow if the history list is deleted in the middle of processing? What if a user or another workflow deletes the list item that your workflow is processing against? These are just two very simple examples of why it is important to verify your objects before you use them. This is going to be different from simple error handling because ideally you want to try some sort of recovery that lets you continue processing. If a list you need does not exist or was deleted, perhaps you can recreate it. If a document is locked, you can wait for it to become unlocked, or you can perhaps notify the user who has it locked that you are waiting for it to be available. There are any number of possible paths you can take if we can first identify a problem before it is too late.

The problem is that you are working with pre-built components. If, for example, you are using the out-of-the-box LogToHistoryListActivity, how can you ensure that the History list for the workflow (which is not known until run time) exists and is available?

There are three approaches to this and other similar problems that fall within the purview of verify before use. The first two of these are available for both sequential and state machine workflows. The third option, available only for state machines, is one of the primary reasons that state machines are the preferred approach for building rock-solid workflows.

  1. Make judicious use of Code activities. If you put one of the out-of-the-box Code activities before every single activity in your workflow that reaches outside of itself or your workflow, you could verify that things are as you need them to be. This has the serious downside of instantly doubling the number of activities in your workflow and muddying the presentation in the designer.

  2. Most activities in your workflows (at least the out-of-the-box activities) have a MethodInvoking property. This property lets you specify a method that the workflow host will call just before it runs the activity. You can add whatever code you need into this method. That code executes just prior to the activity. It has the same effect as placing a Code activity before every other activity in the workflow without cluttering up the designer with multiple extra activities. This approach is nearly perfect for your needs, except for two problems:

    • There is no corresponding method that occurs after the activity is otherwise finished processing. Therefore, anything you do after the activity must be placed into the MethodInvoking property of the next activity. This is not very intuitive, and it is potentially a big problem if the next activity is not known at design time (conditional branching) or if the workflow is updated.

    • If you uncover a problem that you cannot remedy by using code, the only available options in the MethodInvoking property are to throw an error (we will cover error handling shortly) or cancel the workflow. Neither is particularly appealing.

  3. Take advantage of the fact that state machines have essentially multiple individual sequential workflows—StateInitialization, EventDriven, and StateFinalization—contained within each state. This lets you check the environment in the StateInitialization activity before the main activity in the state executes, similar to the MethodInvoking option. However, unlike with MethodInvoking, you can also do some processing after the activity processes—via StateFinalization—or you can easily switch to a different state and therefore a different stream of processing.

Of the three approaches, the third is fairly obviously the best because it gives us the most flexibility. An example might help clarify this approach.

Imagine that you have a workflow operating on a document. At a certain point in the process, the status of the document changes to “Under Review.” There is a column in the SharePoint document library where you record the status, so the workflow has to update the value in the column. Your workflow designer looks something like Figure 4.

Figure 4. Subset of the Document Review workflow shown as a simple sequential workflow

Subset of the Document Review workflow

This part of the process is simple. The review of a document starts, the workflow sets the document status to “Under Review,” and it waits for the review to be finished. The code in the set_StatusCode activity is as follows.

this.workflowProperties.Item["Status"] = "Under Review";
this.workflowProperties.Item.Update();

You test the workflow, and it runs without a problem in your development, Test, and QA environments. So you package it and release it to a pilot group of customers.

Within a week of releasing the code, you start receiving bug reports back reporting failures. Sometimes the process seems to work; sometimes it fails. Can you see the problem? Can you see why it is destined to fail intermittently?

Here’s the problem: every once in a while when your workflow tries to update the status of the document, some other user has the document checked out. When that happens, the workflow fails. Even running as the System Account does not let you sneak past the “Checked Out” barrier.

The solution to this problem is to check whether the document is checked out before you try to update it. If it is not, you should check it out, so that no one else can access it while you work. If it is checked out, you can do any or all of the following:

  • Send e-mail to the user asking him or her to release the document.

  • Switch states to one in which you are waiting for the item to be released.

  • Force the document to be checked in so that you can check it out.

  • Any other action necessary for our process.

Although you could put this code directly into your Code activity, that approach buries the functionality in code and makes things a little harder to maintain. Instead, a better approach might be to use the power of a state machine and spread the functionality across StateInitialization, StateFinalization, and multiple states.

Let’s examine this approach. First of all, the designer for this solution looks like Figure 5.

Figure 5. A subset of the state machine to demonstrate proper defensive coding in a workflow

Subset of State Machine workflow

In the interest of keeping things focused, only those states that are necessary for this part of the example are shown here: UnderReview and WaitForCheckIn. This part of the process shows the workflow coming into the UnderReview state (the arrow at the top left that points downward). By viewing this simplistic subset of the process, you can see that there are two basic paths through the process:

  1. The “main” flow of <Enter> … UnderReview … <Finish>

  2. The alternate flow of <Enter> … UnderReview … Wait … UnderReview

In the case of the second path, if the document is not available to check out, you enter this secondary flow and wait for it to be available. When it is available, you loop back and reenter the UnderReview state. This can continue for as long as necessary for the document to become available. Every change to the document that is saved back into Office SharePoint Server triggers a re-check, but the process only continues when you can obtain exclusive access to the document.

Starting with the UnderReview state, the StateInitialization activity (initStateUnderReview) is where you see whether you can check out the document to update its Status column. The internal process of this activity looks like Figure 6.

Figure 6. StateInitialization designer for the workflow

StateInitialization designer for sample workflow

The heart of this part of the process is the top Code activity (codeDoCheckOut) and the ifElseActivity (ifDocCheckedOut). The Code activity is responsible for seeing if a user currently has the document checked out. If the document is not checked out, the Code activity checks the document out to the System Account. In either case, the name of the user that has the document checked out (either a user or “System Account” if the workflow checked it out) is then stored in a class-level string variable.

After the Code activity does its thing, the process continues on to the ifDocCheckedOut activity. As Figure 6 shows, this ifElseActivity has two branches. The left side of the workflow process was able to successfully check out the document, otherwise the right side occurs. This check is performed with a very simple set of code in the Condition for the ifProcess branch of the ifElseActivity.

private void verifyCheckedOutTo(object sender, ConditionalEventArgs e)
{
    if (sCheckedOutBy.ToLower() == "system account")
    {
        e.Result = true;
    }
    else
    {
        e.Result = false;
    }
}

If the string variable that contains the name of the user that has the document currently checked out indicates System Account, the condition is true; otherwise it is false. Based upon this, the appropriate branch of the IfElseActivity executes.

NoteNote

The name of the user who has the document checked out is stored in a string variable instead of using the full SPUser object. Besides the fact that you really only need the user’s name and storing the rest would be wasteful, we also have to deal with the fact that when our workflow dehydrates, it needs to be able to serialize all of its members to save them in persistent storage. Strings can be serialized; but SPUser cannot.

The first two activities in the ifProcess (left) branch do just what their names imply: set the status of the document and check it back in. Because you have made it to this point in the process, you can be certain that you will not have a problem updating the properties of the document because you have already checked it out. After you set the status as you need to, you check it back in so that other users, or other processes, can access it.

The next activity, setStateFinal is really the next piece that is of interest. Again, the activity is aptly named. It is responsible for transitioning our sample workflow to its final (completed) state. Because you have successfully updated the document properties, your work here is finished. The process can now continue on to its next step, or else, as in the case of the sample process, simply end.

The final piece of the sample that we need to examine is the other branch of the ifDocCheckedOutifElse activity. Looking at this, we can see what happens if our Code activity earlier was unable to check out the document.

Similar to the last activity of the first branch, this branch contains a SetState activity. In this case, it transitions our process to a new state: stateWaitforCheckIn. Here again, this state makes use of the multiple sub-processes available with the state machine, in this case, StateInitialization and EventDriven. In the StateInitialization phase, we take our actions to try to get the document checked in. In this example, that means sending e-mail to the person who has the document checked out. In your case, it could be forcing the document to be checked in, or any number of other possibilities.

The nature of a state machine means that the next phase of this state only executes when the event it is tied to triggers it—hence the event part of the EventDriven name. In this example, we have configured this event to be a change to the document the workflow is running against by using an instance of the onWorkflowItemChanged default activity, the first activity in Figure 7.

Figure 7. EventDriven process in the workflow fires when the payload document is changed

EventDriven process fires when document is changed

When this activity occurs, something has changed with the payload document; we do not know exactly what has changed, because any change on the document will trigger this activity. As you can see in the previous figure, this part of the EventDriven activity is fairly straightforward. On any change to the document, set the state back to UnderReview.

The first thing the UnderReview state does is check whether or not it can check out the document. However, this time through, because the document is available to be checked out (assuming that the user who had it checked out previously has in fact released their hold on it), the second branch of the IfElse activity fires, and the workflow is transitioned to the Final state. Now you're finished.

Although this is a simplistic example, it demonstrates well the idea of defensive coding for workflows. As your “main” flow of the process progresses, it must check to ensure that it can continue. If it cannot, it should divert processing off to a secondary (or tertiary, and so on) flow that can deal with the blocking conditions and when appropriate, redirect processing back to the main process flow to “try again.”

Proactive Error Avoidance

Perhaps Proactive Error Avoidance sounds a little grandiose for a workflow, but in reality, it is nothing out of the ordinary—nothing that any other application you write does not likely do already. All it means is that your application actively tries to prevent errors from occurring. Consider this your first line of defense, but it in no way diminishes the need for good defensive coding. It is also important to note that this activity takes place outside of the workflow itself.

The adage that states the best defense is a strong offense applies here. The best way to prevent problems from disrupting your workflow process is to take steps to prevent the problems in the first place. The key to this element is to know what your dependencies are. This is an element that we discussed earlier. It is now time to examine your dependencies list more closely.

Look for items that you can deal with programmatically, independent of your actual workflow process itself. These are going to be proactive attempts at heading off problems before your workflow is running, as opposed to the more reactive approach of the defensive coding strategies discussed above. For the most part, these items fall into the “required item x does not exist” category: something that your application or workflow created or installed has since been deleted or otherwise made inaccessible.

The mechanism for this type of approach is based entirely upon SharePoint event receivers. For example, if your workflow is dependent upon a certain list item existing, it is important that your workflow installer:

  1. Creates or verifies the existence of the list.

  2. Adds or verifies the item.

  3. Registers an Event Receiver to prevent the item from being deleted.

You can take a similar approach for any of the items supported by SharePoint Event Receivers:

  • List Items

  • Webs

  • Sites

  • List Columns

For example, if your workflow creates a custom column named InternalID that links items in a SharePoint list to your core application, you want to make sure that this column is not removed from lists. To do this, your application should include an Event Receiver such as the following.

public override void FieldDeleting(SPListEventProperties properties)
{
   base.FieldDeleting(properties);
   if (properties.FieldName.ToLower() == "internalid");
   {
     properties.Cancel=true;
     properties.ErrorMessage = @"The InternalID field is required by the
Contoso CaseTrak application. Please see the CaseTrak 
documentation for options and instructions for deleting this 
field";
   }
}

Now, when a user (any user, even an administrator) tries to delete this column from your list, they see the following error page.

Figure 8. Error page shown when Event Receiver prevents deletion of a column

Error shown when Event Receiver prevents deletion

Furthermore, when your workflow runs, it is quite likely that the InternalID field is still available to you. Mission accomplished.

NoteNote

Even with proactive elements such as the one covered in this section in place, defensive coding is still important. If an administrator disables your Event Receiver, the code that prevents the column from being deleted never runs and is therefore unable to stop the column from being deleted. Defensive coding and Proactive Error Avoidance are not mutually exclusive, you must have them both.

Supporting Customizations

Regardless of the nature of your application, one size does not fit all for workflows. It is important to support a certain level of customization, which will likely take one of the following forms:

  • Configuration settings to enable your workflow to run in different environments

  • Customizations to alter the flow of your process based on the customer’s needs

  • The recommended approach is to support both options

Configuration Settings

Supporting configuration settings means that you can let your workflow execute in different environments without having to alter the workflow itself. It is fairly obviously a good idea. Essentially this means that instead of hard-coding settings, you retrieve them from a source that can be edited externally from your workflow. These types of settings could include things such as:

  • Server names (E-mail, Database, Application, and so on)

  • Domain names

  • Impersonation account settings

  • SharePoint Server details: site collections, webs, lists, URLs, and so on

  • Logging details (level, location, and so on)

  • Administrator names

This is just a sample list—you can add to it anything you need.

In looking at this list, it is evident that some of this information is available through the SharePoint Server object model. This is a perfectly acceptable way of supporting configuration settings. For example, if you need to look up an administrator name, you can call SPSite.Owner or iterate through the membership of the SPWeb.AssociatedOwnerGroup property.

The problem comes in for settings that are not available in SharePoint Products and Technologies, for example, impersonation information, domain names, and logging details. Where can you get that information? The answer is simply from a configuration file—no different from any other ASP.NET application. Provided that the information is neither too voluminous (large Web.config files are inefficient) nor too volatile (to edit the file, you must have rights on the server itself), the best place to store it is right in the Web.config itself. If this is not an option, any configuration file is sufficient.

Flow Control

Flow control settings are somewhat different from configuration settings. In configuration settings, the settings information is likely to be stored one time and accessed by every workflow in your farm. In flow control settings, the information is likely to be different for every workflow in your application. Because of this, the best place to capture this type of configuration information is on a workflow form (either Association or Initiation). The information is then stored with the workflow and accessible as follows.

XmlSerializer serializer = new XmlSerializer(typeof(InitForm));
XmlTextReader rdrInitForm = new XmlTextReader(new System.IO.StringReader
    (workflowProperties.InitiationData));
InitForm frmInit = (InitForm)serializer.Deserialize(rdrInitForm);
sMyInitFormPropertyValue = frmInit.MyInitFormProperty;

(InitForm is the class name of your workflow initiation form.)

With what type of information might this option be concerned? Any of the following are possibilities:

  • Reviewer names

  • Approver names

  • Workflow instructions

  • Timeframes for workflow steps, task escalation, and so on

You could add to this list any information known to either the person initiating the workflow or the administrator who initially configures it. It all depends on your workflow and the business process it is supporting.

Rules Engine

One final method for customizing your workflow is far more advanced than either of the other two. In this case, you take advantage of the Rules Engine built into Windows Workflow Foundation and a custom application that enables the rules to be managed externally from the workflow itself. This approach is most appropriate in threshold or timeframe based customizations, such as escalating this task to the user’s manager after x days or assigning this task to the department manager when the purchase order amount is greater than x dollars. A business user can edit the value of x in either scenario without having any contact with or impact upon the other pieces of the workflow. It is also something that your end users can manage separately for different instances of a workflow.

Building a rules management application is beyond the scope of this article. See the Additional Resources section in this article for a link to a sample application that includes full source code and a description. If externally manageable threshold-based rules are supported, or could be supported, in your process, I recommend that you look into this further because it provides your workflows with a significant amount of flexibility at minimal cost.

When Things Go Wrong

Debugging and error handling both rear their ugly heads when things do not go as you planned them in your workflow. So now what do you do? If you are smart, you throw in the towel right now and take up something far more conducive to good mental health—like being a crash test dummy. If you are a glutton for punishment, you try to figure out what went wrong and fix it.

OK, maybe it’s not quite that bad.

Debugging

Let’s start with simple debugging. Fortunately, there is nothing really any different from any other Visual Studio debugging. Attach Microsoft Visual Studio to the W3WP process (with a type of workflow), set a breakpoint where you need it, run your code by launching an instance of the workflow on a document, and your breakpoint is hit just like any other assembly. You have the full power of Visual Studio debugging at your fingertips.

There are a few unique things that you should know:

  • If your workflow fails with an error of Failed on Start, it typically means that your workflow never started, so debugging does not get you anywhere. Look for reasons that would prevent the workflow host from finding and starting your assembly. Check workflow.xml, assembly versions, strong names, and so on. This is likely a deployment issue rather than a code issue.

  • If your workflow fails with an error of Error Occurred, it typically means that your workflow started but encountered an unhandled error while processing. Debugging will likely help in this case, so start the debugger and start stepping through your code. When you find the problem, spend a few minutes figuring out how you can blame it on “bad requirements.”

That one was easy.

Error Handling

First, you must get your terminology straight. In workflows, you do not have “errors,” because error sounds much too negative, as if you actually did something wrong. Instead, you have faults. Isn’t that a much kinder, gentler way of saying somebody messed up?

So, you have fault handling. In workflows, there are two distinct means of handling faults. If you are writing code (either in a Code activity or in a MethodInvoking handler for some other activity), you make use of the standard Microsoft .NET Framework try...catch...finally construct. You would handle these types of errors according to your company’s error-handling policies.

It is different when you are working within the graphical workflow designer. The goal remains the same: you want to handle your errors and let your workflow continue as best as possible, or at a minimum, to shut down gracefully. For information about how to configure fault handling in your workflows, see the Additional Resources section in this article.

Cancellation Handling

Because workflows are inherently long-running processes, there is the possibility that the workflow will be stopped by a user or administrator. Because of this, we need to make sure that we can handle the premature cancellation of our workflow. It would not look good if our workflow started having problems or causing problems because someone canceled it in mid-execution; especially when canceling workflows is an option available right in the user interface. We support allowing our workflow to be canceled by configuring a cancellation handler.

Like the fault handler, the cancellation handler is handled through the visual workflow designer. For information about how to configure cancellation handling in your workflows, see the Additional Resources section at the end of this article.

Logging

Logging is important in any application—more so in an application that is running in a foreign environment. The difference is that, in this type of environment, you are not around to see what is going on. Your application must record the information for you to look at later in the event of a problem. Similarly, if an administrator at the client or partner site is troubleshooting a problem with your software or with the environment in general, the administrator may need to be able to see what your application is doing as part of their troubleshooting.

There are two logical places for your workflow process to record information about its processing: the Windows Event Log and the SharePoint ULS Log. How do you decide which one to use? In general, the answer is straightforward. Use the ULS logs for tracing type information and all errors; use the Event Log only for system errors or critical errors that affect SharePoint Server as a whole or prevent your entire workflow from running on any document.

The difference between internal errors and system errors is somewhat vague and probably depends upon your application and your process. As a rule, an internal error is something that can only reasonably be expected to affect your application and is likely investigated only as part of troubleshooting a problem with your specific process. Examples include:

  • Inability to access a document or list item.

  • SharePoint Server permission problems.

  • Incorrect or missing data (e-mail address, and so on).

System errors, on the other hand, affect more than just your application. System errors may have implications for the whole SharePoint Server environment or even cross out of the SharePoint Server space and impact other unrelated applications. Examples could include:

  • Your main application being inaccessible to your workflow components.

  • Databases not being available.

  • Active Directory Domain Services (AD DS) problems.

  • Other applications not being available.

  • Losing Internet or network connectivity.

One important point to keep in mind is that company IT departments often have processes to monitor the Event Logs on their servers. It is almost a foregone conclusion that they do not monitor the SharePoint Server ULS logs the same way (not that they should not). If your application encounters a situation that is larger than your application or is of such import that you need to raise a flag, writing the information to the Event Log is the way to go.

For information about writing to the Event Log or the ULS Log, see the Additional Resources section in this article.

Phoning Home

For problems strictly within the purview of your application, you might want to consider one additional step: having your application automatically send the information about the error back to your company. This is a potentially slippery slope, fraught with potential legal and privacy implications, but one that you should consider. At the very least, this must be an opt-in mechanism that customers must agree to and one that they can easily change their minds about later.

Consider the following options with this approach:

  • Frequency of reporting   Should your workflow application report the problem immediately or wait and send error reports in a batch?

  • Content of the report   Can customers configure exactly what data points (on an individual basis) are included in the report, or can they simply configure it by level (minimum, typical, full)?

  • Transport mechanism   How will the information be transmitted back to your company—e-mail (probably a bad idea), HTTP, FTP, and so on?

  • **Customer notification   **Will customers be notified (and perhaps copied on) error reports?

  • Level of detail in report   Will the specific error information be reported back to your company, or will you just be notified that an error (or perhaps a type of error) occurred and the details simply recorded in a file that can be retrieved at a later date?

Other items will be included on that list of options depending upon your situation. The answers to all of these questions will be highly dependent and likely left as options for clients or partners to set up according to their needs or policies.

However, this type of functionality is a potential treasure trove of information both for making your product better and for outstanding customer service. For that reason alone, you should consider it. It is not unheard of: Microsoft includes a similar facility for many of their products, including SharePoint Products and Technologies, and many other companies do also.

Deployment

When you are deploying to a customer or partner environment, it is important to have a simple deployment process. If the workflow is part of a standalone deployment, it must be easy for customers to install your workflow. If the workflow is installed with the rest of your application (or a service pack, for example), it must fit seamlessly into your current installation process.

The biggest question to be answered first is if it were not for the workflow elements, would your core application be installing anything to the SharePoint Products and Technologies environment? The answer to this question will drive much of the deployment plans for your workflow. If the answer is yes, your workflow deployment must fit in seamlessly with the rest of your SharePoint Products and Technologies deployment; it cannot feel like an add-on. If the answer is no, your standalone workflow installer must still feel logically like it belongs to your application. You cannot have a highly sophisticated, highly customized installer for your core application and simply a few batch files, and a couple of manual steps for your workflow installer. The impression of your workflow will be that it is not part of your core application and is merely an afterthought that does not receive a whole lot of attention from your company. Although that may not be true, it will be the perception, and unfortunately, in many cases, perception is reality. Therefore, make sure that you put your best foot forward with your workflow installer.

Because it is unlikely that your core application is installed with a batch file, your workflow cannot be either. Unfortunately, the current state of SharePoint deployment practices depend highly on the simple batch file executing a series of Stsadm commands. Fortunately, a few efforts are under way to make SharePoint solutions more acceptable in the deployment world. For more information, see Additional Resources.

Regardless of how your workflow is actually deployed, you must take certain steps to package it for deployment. Any of the deployment options discussed in this article or in the Additional Resources section require that you package your workflow as a SharePoint solution (WSP file) containing a collection of Features. Explaining Features and Solutions in great detail is beyond the scope of this article, but the rest of this section covers them briefly, and describes how to get to the point of having a packaged solution. It assumes that your workflow is finished and fully tested, your assemblies are strongly named and compiled, your workflow forms (either Office InfoPath or ASP.NET) are complete, and any ancillary files or resources are prepared.

At a high level, the steps are as follows:

  1. Creating Features

  2. Creating solutions

  3. Preparing for deployment

Features

A workflow Feature is only slightly different from most other Features in SharePoint Products and Technologies. There are only a few unique elements, but for the sake of clarity, this article covers the whole Feature-building process. A SharePoint Workflow Feature consists of at least two XML files—Feature.xml and your Feature element manifest, typically called Workflow.xml.

Feature.xml

Feature.xml is the file that tells SharePoint Server about your Feature. The structure of this file is largely the same for every Feature you create, differing only in the actual values for the elements. A complete Feature file looks like the following example.

<Feature 
       Id="06de9857-23cb-459e-9b5e-8732fd15b507"
     ImageUrl=”DefensiveCodingSample_Logo.jpg” 
       Title="DefensiveCodingSample"
       Description="This feature is a workflow that demonstrates proper 
          defensive coding strategies"
       Version="12.0.0.0"
       Scope="Site"
       ReceiverAssembly="Microsoft.Office.Workflow.Feature, Version=12.0.0.0, 
          Culture=neutral, PublicKeyToken=71e9bce111e9429c"
ReceiverClass="Microsoft.Office.Workflow.Feature.WorkflowFeatureReceiver"
      xmlns="http://schemas.microsoft.com/sharepoint/"
  <ActivationDependencies />
  <ElementManifests>
    <ElementManifest Location="workflow.xml"/>
    <ElementFile Location="Forms\InitForm.xsn"/>
  </ElementManifests>
  <Properties>
    <Property Key="GloballyAvailable" Value="true" />
    <Property Key="RegisterForms" Value="Forms\*.xsn" />
  </Properties>
</Feature>

The elements of Feature.xml are shown in Table 1.

Table 1. Feature.xml elements

Element Name

Description

Id

GUID that uniquely identifies this Feature.

Title

Name for the Feature, as it appears in the user interface (UI).

Description

Descriptive text that appears under the Title in the Feature list.

ImageUrl

Path to an image that appears in the list of Features alongside the Feature name. You can make the workflow look more professional by putting your company or product logo here.

Version

Not the version of your assembly or really anything about your specific workflow. Instead, it is the version of the Feature schema—for SharePoint Server 2007 this is always 12.0.0.0. For later releases of SharePoint Server, the Feature schema may change, and therefore this version would also change.

Scope

Location that this Feature will be deployed to. Although valid options for Features in general are Farm, Web Application, Site, or Web, it is important to note that workflows can be scoped only to Site (which translates to a Site Collection).

ReceiverAssembly

Feature Receiver that registers your InfoPath workflow forms. Always has a value of "Microsoft.Office.Workflow.Feature, Version=12.0.0.0,Culture=neutral,

PublicKeyToken=71e9bce111e9429c"

Required for InfoPath forms.

ReceiverClass

Feature Receiver that registers your InfoPath workflow forms. Always has a value of "Microsoft.Office.Workflow.Feature.

WorkflowFeatureReceiver"

Required for InfoPath forms.

xmlns

XML namespace for the schema. This is always http://schemas.microsoft.com/sharepoint/ for SharePoint Server 2007 workflows.

ActivationDependencies

Although not typical for workflows, you can specify here the GUID of another Feature that your workflow depends on. If the other Feature is hidden and inactive, it is automatically activated. If the other Feature is visible, it is not automatically activated—you must activate it manually.

Element Manifest

Tells SharePoint Server where to find your element manifest, which is covered later in this article.

ElementFile

Defines a file that is used to support your Feature. It can be an image, a configuration file, and so on. For workflows, it specifies your workflow forms. As specified in the earlier example, it indicates that the form is in a “Forms” subdirectory off the main directory for our Feature.

Property

Name-value pair that lets you specify default values for your Feature. For InfoPath workflow forms, the Register Forms key shown earlier is required.

A skeleton Feature file is created as part of the Visual Studio 2008 project template, so all that you have to do is fill in the blanks. There are other options available for your Feature file, some of which may apply to your workflows for either Windows SharePoint Services or Office SharePoint Server. For more information, see the Additional Resources section in this article.

The Feature file is now complete so you can move on to the element manifest.

Workflow.xml

Although it can have any name—as long as the file name matches what is specified in Feature.xml—the element manifest for workflows is typically called workflow.xml. The purpose of this file is to provide SharePoint Server with the specific information for the workflow. As with Feature.xml, the structure of this file is largely the same for every Feature you create, differing only in the actual values for the elements. A typical workflow.xml file looks like the following example.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Workflow
       Name="DefensiveCodingSample" 
       Description=" This feature is a workflow that demonstrates proper 
          defensive coding strategies”
       Id="08de9c59-24ab-491e-9b7a-97324d1cb507"
       CodeBesideClass="DefensiveCodingSample.Workflow1"
       CodeBesideAssembly="DefensiveCodingSample, Version=1.0.0.0, 
          Culture=neutral, PublicKeyToken=e7d9a5d75ce44b6d"
       TaskListContentTypeId="0x010801"
 InstantiationUrl="_layouts/IniWrkflIP.aspx">
    <Categories/>
    <AssociationData />
    <MetaData>
<AssociateOnActivate>False</AccociateOnActivate>
<StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
     <ExtendedStatusColumnValues>
          <StatusColumnValue>Under Review</StatusColumnValue>
          <StatusColumnValue>Waiting For Check In</StatusColumnValue>
      </ExtendedStatusColumnValues>
<!--Include the following if using InfoPath forms-->
           <Instantiation_FormURN>urn:schemas-microsoft-
               com:office:infopath:InitForm:-myXSD-2007-11-06T15-31-
               39</Instantiation_FormURN>
    </MetaData>
  </Workflow>
</Elements>

Table 2 describes the pieces of this file.

Table 2. Workflow.xml elements

Element Name

Description

Name

Name for the workflow, as it appears in the UI.

Description

Descriptive text that appears under the Name in the workflow list.

Id

GUID that uniquely identifies this workflow.

CodeBesideClass

Name of the class in the workflow assembly. Must take the form of namespace.class.

CodeBesideAssembly

Full four-part (assembly name, version, culture, and PublicKeyToken) of the workflow assembly.

TaskListContentTypeId

(Optional). Unique identifier for the content type assigned to the tasks created by this workflow. If you are using the default task form (that is, not introducing a custom task form), leave this set to the default of 0x010801. If you are not using task forms, you can omit this element.

AssociationUrl

Absolute or server-relative path to the Association form used by your workflow. Make sure that the name of this form is unique. For InfoPath forms, accept the default value specified in the code example. For ASPX forms, specify the path to your form.

InstantiationUrl

Absolute or server-relative path to the Initiation form used by your workflow. Note that the attribute name here really is "Instantiation" and not "Initiation." Make sure that the name of this form is unique. For InfoPath forms, accept the default value specified in the code example. For ASPX forms, specify the path to your form.

ModificationUrl

Absolute or server-relative path to the Association form used by your workflow. Make sure that the name of this form is unique. For InfoPath forms, accept the default value specified in the code example. For ASPX forms, specify the path to your form.

AssociationData

Enables you to specify default values (as valid XML) for items appearing on your Association form. Your Association form must retrieve and parse this content.

MetaData

Enables you to specify additional information for the workflow. Windows SharePoint Services uses the following elements:

  • InitiationType: Manual, #OnItemUpdate, #OnNewItem, #OnMajorCheckIn

  • StatusPageUrl: Absolute or server-relative path to the page used to display the status of a running workflow. If this attribute is deleted, the default status page (_layouts/WrkStat.aspx) is used.

  • ExtendedStatusColumnValues: Enables you to specify unique values for reporting the status of your workflow. For more information, see the State of the Workflow section.

  • AssociateOnActivate: Automatically associates your workflow with the Document content type when the Feature is activated.

  • Association_FormURN: Only applies if you are using InfoPath forms. Uniquely identifies the Association form to be loaded.

  • Instantiation_FormURN: Only applies if you are using InfoPath forms. Uniquely identifies the Initiation form to be loaded.

  • Task0_FormURN: Only applies if you are using InfoPath forms. Uniquely identifies the Task form to be loaded and used for the first task. Subsequent tasks are numbered Task1_FormURN, Task2_URN, and so on.

  • Modification_<GUID>_FormURN: Only applies if you are using InfoPath forms. Uniquely identifies the form to be loaded for the modification.

  • Modification_<GUID>_Name: Name for the workflow modification to be shown in the UI. Replace <GUID> with the actual unique identifier for the modification.

As with the Feature.xml, Visual Studio 2008 creates a skeleton version of this file for you, and all you need to do is fill in the appropriate pieces. There are a couple of other options available for your element manifest file. For more information, see the Additional Resources section at the end of this article.

Solutions

Building a SharePoint solution is not a difficult process, but it is very exacting. You must set up all the pieces exactly right to build the .wsp (solution) file correctly and enable your solution to be deployed properly. We will walk through the process of building the .wsp file at the end of this section. However, before going there, it is important that you understand the purpose and function of a solution package and take a look at the elements that make up a solution: the manifest and the directive (.ddf) file.

Solution packages are simply a mechanism for deploying new functionality to SharePoint Products and Technologies. They pick up a few bells and whistles along the way, and there are a few benefits to using them, but fundamentally, that is all they are; not that it isn’t enough, and it is considerably better than what has been available in the past, but they’re not solving global warming or your grandmother’s rheumatism. However, as a deployment mechanism, they rock, and if you want your workflow components to look and act like a first-rate member of your application you have to use them. No quibbling, so let’s look at how to get you to this utopia of application deployment.

There are two ways to build your solution: manually or by using tools. Normally, I’m a big fan of templates—they can save you a lot of time and effort. However, I think it is more important to understand what those tools are doing for you, so we will cover the manual process here. The Additional Resources section at the end of this article provides links to some tools that can take a lot of the pain out of this process.

NoteNote

This article focuses on building a workflow solution. For a great article about building solutions in general, see Ted Pattison’s August 2007 Office Space column in MSDN Magazine.

Manifest File

The manifest file defines the solution and lists all of the elements that make up the solution. Like Feature.xml and Workflow.xml, the manifest for your solution is an XML file, this time adhering to the schema specified in Solution Schema. The following shows a sample manifest file.

<Solution xmlns="http://schemas.microsoft.com/sharepoint/" 
     SolutionId="78de9c59-2fab-4a1e-9b7a-1732431cbe07" >
    <Assemblies>
         <Assembly DeploymentTarget="GlobalAssemblyCache"
     Location="DefensiveCodingSample.dll" />
         </Assemblies>
    <FeatureManifests>
         <FeatureManifest Location="DefensiveCodingSample\Feature.xml"/>
    </FeatureManifests>
</Solution>

Table 3 provides details on the elements of Manifest.xml.

Table 3. Manifest.xml elements

Element

Description

SolutionId

GUID that uniquely identifies your solution.

Assemblies

Add one node for every assembly that is part of your solution

DeploymentTarget

Tells the solution installer where to put the DLL. Valid options are WebApplication or GlobalAssemblyCache.

Location

Tells the solution installer where to find your DLL.

FeatureManifest

Tells the solution installer where to find your Feature.xml file.

NoteNote

Those are the primary elements of the manifest file that are used in workflows. There are quite a few other options. If you are curious, you can review the schema file located at the link provided above.

Directive (DDF) File

The .ddf file is the final piece necessary for building your solution. It is this file that is actually used to define the structure of the solution file. During the process of building your .wsp (solution) file, the MakeCAB utility (more on this in a moment) reads the .ddf file and packages all the files for as specified in the .ddf file.

Although your solution file has a file extension of .wsp, it is really nothing more than a standard CAB file with a different extension. If you change the extension back to .cab, you can open the file in Windows Explorer and examine the contents.

The following shows a sample .ddf file.

.OPTION EXPLICIT      
.Set CabinetNameTemplate=DefensiveCodingSample.wsp     
.Set DiskDirectoryTemplate=CDROM 
.Set CompressionType=MSZIP
.Set UniqueFiles="ON"
.Set Cabinet=on
.Set DiskDirectory1=Package


manifest.xml                                                  
manifest.xml
GAC\DefensiveCodingSample.dll                                        
DefensiveCodingSample.dll
TEMPLATE\FEATURES\DefensiveCodingSample\feature.xml          
DefensiveCodingSample\feature.xml
TEMPLATE\FEATURES\DefensiveCodingSample\workflow.xml     
DefensiveCodingSample\workflow.xml
                                             

;*** add Workflow forms:
TEMPLATE\FEATURES\DefensiveCodingSample\Forms\InitForm.xsn     
DefensiveCodingSample\Forms\InitForm.xsn

State of the Workflow

SharePoint workflows report their status by creating a column in the default view for the list or library that the workflow is running in. The column is named with the name of the workflow. The status is also shown on the workflow status page. Except for errors, the default values typically seen for status are In Progress or Completed. For a sequential workflow, this is likely sufficient, and it is really all one would expect because there really is not any other defined state for the workflow to be in.

State machine workflows, on the other hand, by their very nature have additional defined states. Wouldn’t it be great to report a status of the actual state the workflow is in at that moment? Well, it’s time to celebrate, because you can do just this, quite easily.

Previously, when we were covering the contents of the workflow.xml file, we looked briefly at the <ExtendedStatusColumnValues> tag within the <Metadata> element. By specifying custom values here that match the names of your states, you can set those values into the status column in your list. For example, you can specify values such as the following.

<ExtendedStatusColumnValues>
    <StatusColumnValue>Under Review</StatusColumnValue>
    <StatusColumnValue>Waiting For CheckIn</StatusColumnValue>  </ExtendedStatusColumnValues>

Now, in your workflow, you can reference those values and have them appear in the status field. You do this by using the “other” Set State activity—that is, not the one used by a state machine workflow to transition from one state to another. It is the activity in the toolbox that has an icon that looks like this: Toolbox activity icon

After you add that activity to your workflow at the appropriate spot (typically in StateInitialize), you can set your status to one of the new entries you added in workflow.xml by creating a MethodInvoking method and adding the following code to it.

((Microsoft.SharePoint.WorkflowActions.SetState)sender).State = ((Int32)SPWorkflowStatus.Max) + 1;

You explicitly cast to the SetState activity that you want (referencing the full name of the class to avoid confusion with the state machine SetState activity). The +1 added to the SPWorkflowStatus.Max indicates the second entry in your workflow.xml ("Waiting for Check In"), because the list is zero-based.

Figure 9. Waiting for check-in status in Workflow Information

Sample DDF file

The top of the file sets up some variables (see Table 4) that configure how the .wsp file is generated; they are generally self-explanatory.

Table 4. Variables in .ddf file that configure generation of the .wsp file

Element

Description

CabinetNameTemplate

Specifies the name of the resulting .wsp file.

DiskDirectoryTemplate

Places all generated CAB files in a single directory.

CompressionType

Algorithm used for compressing files.

UniqueFiles

Indicates that all files in the CAB must have unique names.

DiskDirectory1

Specifies a subdirectory into which CAB files are placed.

Typically, this top part of the .ddf file is the same (except for the CabinetNameTemplate parameter) for all solutions that you build.

The rest of the file is unique to the specific solution that you are building. It specifies the files that are packaged into the .wsp in addition to the following:

  • The first part of each line is the source location so that MakeCAB can read them to add them to the CAB. Note that this location is relative to the current directory, which is typically going to be either the location of the DDF or else the location of the MakeCAB utility.

  • The second part of each line is the destination location of each file within the CAB itself. In the example above, the Manifest.xml and our DLL will each be in the root of the CAB, the Feature.xml file will be in the root of our Feature (“DefensiveCodingSample”) folder, ACTIONS file will go into a folder path of 1033\Workflow. Remember that when the Solution is deployed, this location is referenced in the TemplateFile element of Manifest.xml and is relative to the \Template folder.

For the files portion of your .ddf file, it is important that you include each source/destination pair on one line. They are broken into two lines in our listing here just for readability.

To understand the file system structure that is required for this .ddf file to work properly, examine Figure 10. It shows a view of our project with all of the folders and files laid out as the DDF and MakeCAB utilities expect to find them. Notice the Utilities folder, which contains a few batch files for building and testing your solution file, and also the MakeCab.exe application. See Additional Resources for information about how to download a copy of MakeCAB.exe, as part of the Microsoft Cabinet SDK. The rest of this solution is available in the source code download for this article.

Figure 10. The directory structure required for the solution

Directory structure required for solution

With that, your .ddf file is complete. You can move on to building your .wsp file.

Building the Solution File

The last step to cover is actually building the solution (.wsp) file itself. This article has covered how to construct the files and the file structure you need for this. Now you can create the file itself. The good news is that you can handle building the .wsp file with two lines in your MakeCAB.cmd file (available in the source code download for this article).

cd ..

Utilities\MakeCab /F DefensiveCodingSample.ddf

After you run this batch file, your .wsp file is available in the DeploymentFiles\Package directory in your project folder. If you want to view the contents of the .wsp file, you can change the extension to .cab and open it in Windows Explorer; just make sure to change the extension back when you are finished.

Wrapping Up Deployment

As mentioned at the beginning of our deployment coverage, it is important that the deployment process for your workflow look professional and look like it belongs with the rest of your application deployment. Because of this, the typical batch files used for deployment (including the Deploy.cmd and the UnDeploy.cmd files in the source code download, which are good for testing your solution package) are not sufficient. Instead, you must look into something a little more polished. See Additional Resources for links to a few options.

Documenting Your Workflow

As you probably expect, documentation is critical. It is rare that a company lets you run anything that is not well documented in their environment. Even if you could somehow go past that barrier, it is not in the best interests of your workflow to be undocumented.

Taking that one-step further, there should be at least five levels of documentation:

  1. End-user documentation   Information for the people who will use your workflow processes.

  2. Administrator documentation   Information for the people who will install, configure, and maintain, your workflow process in the client or partner environment.

  3. Support documentation   Information for people in your company who are responsible for assisting customers with problems or questions about your workflow.

  4. Technical documentation   Information for the developers and engineers who are responsible for maintaining, fixing bugs in, and enhancing your workflow.

  5. Source code   The ultimate documentation of any custom application is the source code. The barrier to entry for this documentation is fairly high, but the buck stops here.

The first two of these are obviously customer facing, so they must play the dual role of being both marketing material and support material. They must be well written, contain many pictures, and not make any assumptions as to the technical aptitude, ability, or interest of the reader. Although they obviously cannot be condescending, they also cannot assume that the client understands technology. So, for example, a sentence such as, "Upon reaching a state in which the process is waiting upon an external event, it will automatically be dehydrated by the workflow host and written to persistent storage until the event is raised, at which point it will be rehydrated and continue processing" is not appropriate for this type of documentation. (Come to think of it, a sentence such as that may not be appropriate for any type of documentation that you actually want people to read.) Make your customer-facing documentation clear and concise, and your workflow and application will stand out from the crowd.

User documentation needs only to help people use the workflows. If your workflows are configurable, this documentation probably has to be custom written for each installation. This is not to say that you cannot start with elements largely written or even templates that just have customization details filled in. However, it does mean that you must revisit this documentation for each client or partner. You may even want to consider making this online documentation that is deployed as part of your workflow and available to users directly on or from the screens in which they interact with the workflow. Primarily this means adding elements directly to the workflow forms or else providing the documentation in separate files and linking to those files from the workflow forms. The more context-sensitive you can make this documentation, the better. Rather than simply providing a monolithic HTML file, look for ways in which you can point users directly to the information about the specific screen they are on or area of the process they are in.

The administrator documentation probably does not have to be so customized. It must cover all the options for configuring and maintaining your workflow, but it is sufficient to have a worksheet included that records all the customizations that were made for the specific implementation.

The next level of documentation, support documentation, is targeted at internal personnel, so it does not need to have quite the same degree of marketing spin as the previous documentation. This documentation must be focused primarily on the "what" aspect of your application (what features and functionality are available) and some of the "how" (the steps necessary to achieve certain functionality).

The intended audience for the fourth type of documentation is strictly technical, and so the document must be as well. Technical documentation explains the "how" aspects of your workflow in painstaking detail. People reading this level of documentation understand technology and expect it to be the main part of what they read. There should be no high-level overviews, and no feature or functionality lists; for that information, they can read the other types of documentation.

The final type of documentation is the source code itself. Perhaps it is not typical to think of source code as documentation. But by this point, if the code is well written, commented, and maintained, that is exactly what it is. If the higher-level documents say that the application can perform function x, but it does not appear to do so, the final judge as to whether x is available is the source code itself.

Summary

To a certain extent, building workflows for a customer or partner environment is no different from building solid workflows for your company’s enterprise. You still must produce a solid design and deliver a solid product. The difference comes into play when you think about the lack of control you have in an external environment. Things that, perhaps, you can handle through business rules or separately set security in your own environment must be locked down programmatically for external environments.

In many ways, too, deploying to an external environment means that you cannot make assumptions about the environment. Each assumption highlights defined dependency requirements, and if you have too many, you will make the barrier to entry too high, and clients or partners will not deploy your solution.

We covered a lot of ground in this article. To summarize it all here would be difficult, but I will leave you with the following. The four most important elements of producing a workflow for a customer or partner environment are:

  • Planning   Spend time thinking about what you are going to build and support before you go any further. Know and understand the strengths and weaknesses of SharePoint workflows and how they will affect your project.

  • Error Handling   Just expect that errors will happen, and make sure that you can recover gracefully. Simple, intuitive error messages and an easy way for administrators at the client or partner site to troubleshoot will go a long way to enhancing the reputation of your product.

  • Security   It just plain needs to be rock solid. Workflows introduce another potential attack vector for your application. Just make sure you lock it down.

  • Simplicity   From deployment to administration to usage, if it is too complicated, people will not use it. Think about this as you progress through every step of your workflow development. Test for this. Look for ways to make forms, processes, or other user interactions easier. Let the application do the heavy lifting; do not make your users or administrators think too much.

Additional Resources

Throughout this article, I touched upon a number of topics that were not directly related to our task at hand. Rather than leave you at the mercies of a search engine, here are some links that will help you find the information you are looking for:

Tools