Building a Custom Workflow Initiation Form Using Visual Studio
I first want to mention that I learned how to do this by following the four part workshop written by Robert Shelton. This is a very comprehensive workshop that gives you access to all of the source code and documentation. Where Robert’s workshop walked you through building a complete workflow in Visual Studio including the Association and Initiation, my particular needs at the time were focused solely on an Initiation form. In this post, I will attempt to condense this lesson as concisely as possible.
I am using Visual Studio 2005 for this process, so all of my screenshots will be from that version.
Let me first address the question “why Visual Studio?” Initiation forms can easily be built using InfoPath. The answer is simple: an Initiation form built in InfoPath doesn’t easily (if at all) allow you to access data from the list item on which you are running the workflow.
What you can expect from this post
This post is not a comprehensive tutorial on how to build a custom workflow. You should already have familiarity with building basic workflows using Visual Studio. There are two parts to building a workflow that uses a custom Initiation form: creating the Initiation form and creating the workflow itself. This post focuses most of its attention on building the initiation form. I only highlight the important aspects of building the workflow itself as it pertains to this situation.
To demonstrate how this is built, I will present an example that I recently built. Our corporate intranet portal contains a list of project information. I needed to produce a workflow that would allow a user to publish that information to our public website hosted on a different farm. Before publishing, the user should have the ability to edit the data to get it “website ready.”
Setting up the Initiation Form
Create an ASP.NET Web Site Project
To build an initiation (a.k.a. instantiation) form, you first need to create a new project in Visual Studio. I chose to use the ASP.NET Web Site template in Visual Studio (File > New > Web Site). The first question you may ask is where you will locate this web site and how it will be integrated into a SharePoint environment. One of your options is to locate the solution in the LAYOUTS folder of your SharePoint configuration. This is actually the simplest solution since it doesn’t require any other modifications to SharePoint’s configuration. It also has the benefit of being available from any web application on the server.
In the New Web Site dialog, be sure that Location is set to HTTP. You’ll notice in the screenshot that the URL is set to store the solution in the /_layouts directory, as described above. This will have the effect of storing your solution in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS.
Once your new solution has been created, feel free to delete the Default.aspx file. This file will not be needed. Next you can chose to create a new folder that will hold the files for the Initiation form. This is not required, but helps organize these files from others, particularly if you were to later add an Association, Modification, or Edit Task form to the solution.
Create the Initiation Form
Add a new ASP.NET form to the folder (Right-click > Add > New Item > Web Form). Name this form InitiationForm.aspx. If you are using Visual Studio 2008, be sure the “Select Master Page” option is clear.
Now that you have your default web form code, you’ll need to edit it. Let’s start with the form code (.aspx). The one key point to note here is that Design view will not work properly when you start to introduce SharePoint components and directives into the code. This is explained in more detail in Part 2 of Robert Shelton’s workshop. For simplicity, just work solely in Source view.
You’ll need to include the following key elements in your .aspx code, as follows:
- @Page Directive
- References to Microsoft.SharePoint
- Reference to Microsoft.SharePoint.Utility
- ContentPlaceHolder tag
- FormDigest control
At a minimum, your code should look something like the following screenshot.
Write the code for your form inside the ContentPlaceHolder control. I won’t get into detail here – just build a standard asp.net form that meets your needs.
Coding the Initiation Form Code-Behind
Now it’s time to move on to the code-behind page (.aspx.cs). How you layout your methods is up to you. There are several key elements that you need to focus on. Since there is a lot to take in, I’ll first outline these points, and then discuss each in more detail.
- References and using statements
- Use the site’s master page
- Get workflow parameters
- Get workflow association information
- Get list information
- Serialize form data
- Submit form data to the workflow
References and Using Statements
You’ll need to add a reference to the SharePoint.dll to your project, which should be found in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI\. Once you’ve included the dll, you need, at a minimum, the following using statements:
- using Microsoft.SharePoint;
- using Microsoft.SharePoint.WebControls;
- using Microsoft.SharePoint.Workflow;
- using Microsoft.SharePoint.Uitlities;
- using System.IO;
- using System.Text;
- using System.Xml;
- using System.Xml.Serialization;
Use the Site’s Master Page
You may have been wondering how you would get the form to inherit the look and feel of the SharePoint site. It’s quite simple. I included this code in the OnPreInit() method, as shown below.
Get Workflow Parameters
Information about the workflow is passed to the workflow as parameters via the URL. Specific information about these parameters can be found at http://msdn.microsoft.com/en-us/library/ms481192.aspx. In this example, we are specifically interested in the following:
- TemplateID: GUID of workflow association (not to be confused with the Association form)
- List: GUID of the list to which the item belongs
- ID: ID of the list item on which the workflow is started
In the code snippet below, you’ll see that I am declaring class level variables and retrieving the data from the URL string in the getWorkflowParameters() method. I call this method from the Page_Load() method, where I do some other processing as well.
Get Workflow Association Information
Now that I have the Workflow Association GUID, I can get the information that I need about this workflow. Most importantly, I need to get the workflow template, which is the xml file that holds the workflow data. Again, I’m declaring some class level variables first.
Get List Information
Since we got the list GUID and list item ID that the workflow is running on, we can retrieve the list item object as shown below. Once you have the list item object, you can then retrieve data from the item and use it in your form just as you normally would retrieve and use list item information using the object model. In my situation, I pre-populated the form fields with data from the list item. I did this in the Page_Load() method.
Serialize Form Data
Up to this point, the code has focused on setting up the form prior to processing. Now it’s time for some code that will be used when the form is submitted.
The first thing we need to do is serialize the form data so that we can send it to the workflow. The workflow expects this data to be in XML. To accomplish, first I set up a class to represent the data structure of this form data. That code would look something like this:
As you can see in the code below, the method to serialize the data first populates the InitiationData object with values from the form. It then serializes the data into XML.
Submit Form Data to the Workflow
Code to send the workflow data and start the workflow is placed in the form submit button’s click event. Here the code first calls the method to serialize the data as described above.
Building the Workflow to Accept Initiation Data
Now that you have your initiation form built, it’s time to focus on the workflow itself. You should already have familiarity with building custom workflows using Visual Studio. I will only focus on the key elements that pertain to using a custom Initiation form.
The first thing you need to do is to tell the workflow to use the initiation form that you built in the other project. To do this, simply set the InstantiationUrl element in the workflow.xml file to the proper path to the initiation form:
Deserialize Workflow Data
Now that your workflow will use the initiation form, you need to retrieve its data. To do this, build a serializable class that will hold the data from the initiation form. This class is identical to the class that you built in the other project, as follows:
Once you have this, you can then deserialize the data from the workflow:
Place this code wherever you need to within the workflow, and process as necessary.
As you can see, editing a standard workflow to use initiation form data is pretty straightforward. The key is to build the initiation form properly, and to place it in a location that is accessible to the workflow. In this discussion, I created an ASP.NET Web Site project located under the LAYOUTS directory of the SharePoint web application that holds the initiation form. I pull information about the workflow from parameters in via the URL so that I can get the workflow template and information about the list I am working. Once I process the form, I serialize the form data into xml, and pass it to the workflow. The workflow then de-serializes the data and continues processing as normal.