Accessing Data from Workflow Association and Initiation Forms in Windows SharePoint Services 3.0

Summary: Learn how to access data from workflow association and initiation forms in Windows SharePoint Services 3.0. (46 printed pages)

Joel Krist, Akona Systems

January 2008

Applies to: 2007 Microsoft Office System, Windows SharePoint Services 3.0, Microsoft Visual Studio 2005 Extensions for Windows SharePoint Services 3.0

Contents

  • Overview

  • Keys Steps to Accessing Data from Workflow Association and Initiation Forms

  • Create a SharePoint Sequential Workflow Library Project in Visual Studio 2005

  • Design the Workflow

  • Set Workflow Activity Properties

  • Initialize Task Property Variable

  • Add Code that Works with Workflow Association and Initiation Forms

  • Create an ASPX Forms Class Library Project

  • Add References to the Class Library

  • Add ASPX Forms and Supporting Code to Class Library

  • Strong Name Sign the Workflow Library and Form Assemblies

  • Deploy the Workflow

  • Conclusion

  • Additional Resources

Watch the Video

http://wm.microsoft.com/ms/msdn/office/2007OfficeVisualHowTos/WSSAccessingDatafromWorkflowAssociationandInitiationForms.wmv

Overview

A workflow allows a business process to be attached to items in Windows SharePoint Services 3.0. This process can control almost any aspect of an item in Windows SharePoint Services 3.0, including the life cycle of that item. Workflows can be as simple or complex as business processes require.

Workflow association and initiation forms are displayed for users to complete before any workflow actually starts. These forms can be used to enable users to set parameters and other information for the workflow in advance. Association forms address how the workflow applies to a specific list, library, or content type; initiation forms address how the workflow applies to a specific SharePoint item.

The Visual Studio 2005 Designer for Windows Workflow Foundation provided with the Microsoft Visual Studio 2005 Extensions for .NET Framework 3.0 (Windows Workflow Foundation) provides a means to rapidly develop workflows by using a graphical interface that allows you to use your knowledge of the Microsoft Visual Studio development environment. This article and related video illustrate how to create a Windows SharePoint Services 3.0 workflow that accesses data from workflow association and initiation forms.

The steps discussed in this technical article require that the following applications have been installed on your development computer:

  • Windows SharePoint Services 3.0

  • Microsoft Visual Studio 2005

  • Microsoft Visual Studio 2005 Extensions for .NET Framework 3.0 (Windows Workflow Foundation)

  • Microsoft Office SharePoint Server 2007 Software Development Kit (SDK)

Keys Steps to Accessing Data from Workflow Association and Initiation Forms

There are seven key steps necessary to access data from workflow association and initiation forms.

  • Creating a SharePoint Sequential Workflow Library project in Microsoft Visual Studio 2005.

  • Designing the workflow outline using Visual Studio 2005 Designer for Windows Workflow Foundation.

  • Setting the properties of the workflow activities.

  • Adding code to the workflow that works with the data specified on the workflow association and initiation forms.

  • Adding a Class Library project to the solution that contains ASPX forms and supporting code files to implement the workflow association and initiation forms.

  • Strong name signing the workflow library and ASPX pages class library assemblies.

  • Deploying the workflow.

Create a SharePoint Sequential Workflow Library Project in Visual Studio 2005

To create a SharePoint Sequential Workflow Library project

  1. Start Visual Studio.

  2. On the File menu, select New, and then Project. The New Project dialog box appears.

  3. In the Project Types pane, select Visual C# and then select the SharePoint category.

  4. In the Templates pane, select Sequential Workflow Library. Specify FormDataWorkflow for the project's name, specify a location for the project and click OK. Visual Studio creates a new solution containing the workflow library project.

    Figure 1. Creating a SharePoint Sequential Workflow Library Project

    Create sequential workflow library project

Design the Workflow

The workflow created with this walkthrough is very simple. Upon activation it creates a new task associated with the list item and then waits for the task to be completed. After the task has been completed, the workflow executes a code activity that updates fields in the list item with the data values specified by the user on the workflow association and initiation forms. The workflow then deletes the task from the task list.

To design the workflow

  1. In Solution Explorer, expand the FormDataWorkflow project node and then double-click the Workflow1.cs file that was created by Visual Studio. The initial workflow outline is displayed in the Workflow Designer and shows the onWorkflowActivated activity that was added by Visual Studio.

    Figure 2. Initial Workflow Outline

    Create initial workflow outline

  2. Open the Visual Studio toolbox and drag a CreateTask, OnTaskChanged, Code, and DeleteTask activity, in that order, to the workflow outline.

    Figure 3. Final Workflow Outline

    Create final workflow outline

Hinweis

If the SharePoint workflow activities are not visible in the Visual Studio toolbox, you can load them by performing the following steps.

  • In workflow design mode, right-click the Toolbox. Select Choose Items.

  • In the Activities tab, browse and select the Microsoft.SharePoint.WorkflowActions.dll file located in the %programfiles%/Common Files/Microsoft Shared/web server extensions/12/ISAPI folder.

Set Workflow Activity Properties

The Workflow Designer displays red exclamation marks next to each of the workflow activities added in the previous step. This occurs because the activities have not had their correlation token property set yet. A correlation token is a unique identifier that enables mapping between the objects in a workflow and the environment that is hosting the Windows Workflow Foundation (WF) workflow runtime.

  1. Open the workflow code file by right-clicking the Workflow Designer surface and selecting the View Code menu item. The Workflow1.cs file is displayed in the code editor.

  2. Add the following using statement below the using statements that are generated by Visual Studio.

    using Microsoft.SharePoint.Workflow;
    
  3. In the Workflow1.cs file, add the following lines of code to the body of the Workflow1 class just below the code that is generated by Visual Studio that defines the workflowId and workflowProperties variables.

    public Guid taskId = default(System.Guid);
    public SPWorkflowTaskProperties taskProperties =
        new SPWorkflowTaskProperties();
    
  4. Switch back to the workflow design view, right-click the createTask1 activity and select Properties.

  5. In the Properties pane, specify taskToken for the value of the CorrelationToken property and press Enter. A plus sign is displayed to the left of the CorrelationToken property.

  6. Click the plus sign to display the OwnerActivityName property and set its value by expanding the property value drop-down list box and selecting Workflow1.

  7. Select the taskId property and then click Ellipses. The Property Bind dialog is displayed.

  8. Select the taskId property that you created in step 3 above and click OK.

    Figure 4. Binding the TaskId Property

    Bind TaskId property

  9. Select the taskProperties property and then click Ellipses. The Property Bind dialog is displayed.

  10. Select the taskProperties property that you created in step 3 above and click OK.

    Figure 5. Binding the TaskProperties Property

    Bind taskProperties property

  11. Right-click the onTaskChanged1 activity and select Properties.

  12. In the Properties pane, select the CorrelationToken property and set its value by expanding the property value drop-down list and selecting taskToken.

  13. Select the taskId property and then click Ellipses. The Property Bind dialog is displayed.

  14. Select the taskId property that you created in step 3 above and click OK.

  15. Select AfterProperties and then click Ellipses. The Property Bind dialog is displayed.

  16. Select the taskProperties property that you created in step 3 above and click OK.

  17. Right-click the deleteTask1 activity and select Properties.

  18. In the Properties pane, select the CorrelationToken property and set its value by expanding the property value drop-down list box and selecting taskToken.

  19. Select the taskId property and then click Ellipses. The Property Bind dialog is displayed.

  20. Select the TaskId property that you created in step 3 above and click OK.

Initialize Task Property Variable

Currently the taskId variable used for the TaskId property of the task-related activities has a default GUID value of all zeros, and the title property of the taskProperties variable has not been set. Your next step is to initialize the taskProperty variables.

To initialize the taskProperty variables

  1. In the workflow designer, double-click the createTask1 activity. Visual Studio switches the Workflow1.cs file and displays the body of the createTask1_MethodInvoking method. This method will be called just before the createTask1 activity is started.

  2. Add the following code to the body of the createTask1_MethodInvoking method.

    taskId = Guid.NewGuid();
    taskProperties.Title = "Task for " + workflowProperties.Item.Name;
    

Add Code that Works with Workflow Association and Initiation Forms

You have now set the properties of the task-related workflow activities.. Your next step is to add code to the code activity that will work with the data from the workflow association and initiation forms.

To add code for the workflow association and initiation forms

  1. In Solution Explorer, right-click the FormDataWorkflow project and select Add and then select New Item. The Add New Item dialog box is displayed.

  2. Select the code file template, specify a name for the FormData.cs file, and click Add. Visual Studio opens the empty FormData.cs file.

    Figure 6. Adding FormData.cs

    Add FormData.cs file

  3. Add the following code to the FormData.cs file.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Xml.Serialization;
    
    namespace FormDataWorkflow
    {
        [Serializable()]
        public class FormData
        {
            private string field1 = default(string);
            public string Field1
            {
                get
                {
                    return this.field1;
                }
                set
                {
                    this.field1 = value;
                }
            }
            private string field2 = default(string);
            public string Field2
            {
                get
                {
                    return this.field2;
                }
                set
                {
                    this.field2 = value;
                }
            }
            private string field3 = default(string);
            public string Field3
            {
                get
                {
                    return this.field3;
                }
                set
                {
                    this.field3 = value;
                }
            }
            private string field4 = default(string);
            public string Field4
            {
                get
                {
                    return this.field4;
                }
                set
                {
                    this.field4 = value;
                }
            }
            private string field5 = default(string);
            public string Field5
            {
                get
                {
                    return this.field5;
                }
                set
                {
                    this.field5 = value;
                }
            }
            private string field6 = default(string);
            public string Field6
            {
                get
                {
                    return this.field6;
                }
                set
                {
                    this.field6 = value;
                }
            }
        }
    
        public class Helper
        {
            public static FormData DeserializeFormData(string xmlString)
            {
                using (MemoryStream stream =
                    new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
                {
                    XmlSerializer serializer =
                        new XmlSerializer(typeof(FormData));
                    FormData data =
                        (FormData)serializer.Deserialize(stream);
                    return data;
                }
            }
        }
    }
    
  4. In the workflow designer, double-click codeActivity1. Visual Studio switches the Workflow1.cs file and displays the body of the codeActivity1_ExecuteCode method.

  5. Add the following code to the body of the codeActivity1_ExecuteCode method.

    SPListItem item = workflowProperties.Item;
    FormData associationFormData = 
        Helper.DeserializeFormData(workflowProperties.AssociationData);
    FormData initiationFormData = 
        Helper.DeserializeFormData(workflowProperties.InitiationData);
    
    item["Field1"] = associationFormData.Field1;
    item["Field2"] = associationFormData.Field2;
    item["Field3"] = associationFormData.Field3;
    item["Field4"] = initiationFormData.Field4;
    item["Field5"] = initiationFormData.Field5;
    item["Field6"] = initiationFormData.Field6;
    
    item.SystemUpdate(false);
    

    The code shown above uses the Helper.DeserializeFormData static method, which is defined in the FormData.cs file, to deserialize the workflow association and initiation form data that is passed to the workflow into an instance of the FormData class. The properties of the FormData class instance are then used to set the values of the corresponding fields on the list item that the workflow is associated with.

    Hinweis

    For the sake of simplicity, this code assumes that the list associated with the workflow has text columns named Field1, Field2, and so on. In a real-world solution, you could create a site content type and associate the workflow with the content type. This would guarantee that the list that is associated with the workflow has all the required columns.

    After adding the code shown above, the FormDataWorkflow project should build successfully.

Create an ASPX Forms Class Library Project

This technical article illustrates how to implement workflow association and initiation forms using ASPX forms. The ASPX forms are stored in their own assembly that is created as a Class Library project in Visual Studio. To create an ASPX forms class library that contains the association and initiation forms for the workflow that you created previously, follow the steps below.

To create an ASPX forms class library

  1. In Solution Explorer, right-click the FormDataWorkflow solution, select Add and then select New Project. The Add New Project dialog is displayed.

  2. In the Project Types pane, select Visual C# and then select the Windows category.

  3. In the Templates pane, select Class Library. Specify FormDataASPXPages for the project's name and click OK. Visual Studio adds the class library project to the solution.

    Figure 7. Creating a Class Library Project

    Create class library project

  4. In Solution Explorer, right-click the Class1.cs file created by Visual Studio and then select Delete. Click OK when Visual Studio warns that the file will be deleted permanently.

Add References to the Class Library

The next step is to add references to the necessary SharePoint and .NET assemblies to the class library. To add references, follow the steps below.

To add SharePoint and .NET assembly references to the class library

  1. In Solution Explorer, right-click the FormDataASPXPages project and select Add Reference. The Add Reference dialog is displayed.

  2. On the .NET tab, locate and select the following components:

    • System.Drawing (System.Drawing.dll) System.Drawing.Design (System.Drawing.Design.dll)

    • System.Web (System.Web.dll)

    • System.Workflow.ComponentModel (System.Workflow.ComponentModel.dll)

    • Windows SharePoint Services (Microsoft.SharePoint.dll)

    It is possible to select more than one component at a time by holding down the Ctrl key while clicking on the component names. After you have selected all the components you want to include, click OK to add the references to the project.

Add ASPX Forms and Supporting Code to Class Library

The final step is to add the ASPX forms and supporting code files to the class library project. The code shown below is based on the Feedback Collection workflow sample that is provided with the Windows SharePoint Services 3.0 SDK. To add the ASPX forms and supporting code files to the FormDataASPXPages project, do the following:

To add ASPX forms and supporting code to class library

  1. In Solution Explorer, right-click the FormDataASPXPages project, select Add and then select New Item from the menu. The Add New Item dialog box is displayed.

  2. Select the Code File template and specify FormDataAssocForm.aspx for the file name.

    Figure 8. Adding Files to the Class Library Project

    Add files to class library project

  3. Click Add to add the file to the project.

  4. Repeat steps 1 through 3, specifying different file names, to add the following files to the FormDataASPXPages project:

    • FormDataAssocForm.cs

    • FormDataInitForm.aspx

    • FormDataInitForm.cs

    • FormDataPages.cs

  5. Add the following code to the FormDataPages.cs file.

    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.IO;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.Xml;
    using System.Xml.Serialization;
    
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Workflow;
    
    namespace FormDataAspxPages
    {
        public enum FormType
        {
            Association,
            Initiation
        }
        public class WFDataPages : LayoutsPageBase
        {
            protected SPList List;
            protected SPContentType m_ct;
    
            protected TextBox textboxField1;
            protected TextBox textboxField2;
            protected TextBox textboxField3;
            protected TextBox textboxField4;
            protected TextBox textboxField5;
            protected TextBox textboxField6;
    
            protected string m_strQueryParams;
            protected bool m_bContentTypeTemplate = false;
    
            #region OnLoad
    
            protected override void OnLoad(EventArgs ea)
            {
                base.OnLoad(ea);
    
                // Ensure that we get the context variables.
                EnsureRequestParamsParsed();
    
                // Check for permissions.
                SPBasePermissions perms =
                    SPBasePermissions.Open | SPBasePermissions.ViewPages;
                if (m_bContentTypeTemplate)
                    perms |= SPBasePermissions.AddAndCustomizePages;
                else
                    perms |= SPBasePermissions.ManageLists;
                Web.CheckPermissions(perms);
            }
    
            // Ensure the we get the context variables.
            protected void EnsureRequestParamsParsed()
            {
                string strListID = Request.QueryString["List"];
                string strCTID = Request.QueryString["ctype"];
                if (strListID != null)
                    List = Web.Lists[new Guid(strListID)];
                if (strCTID != null)
                {
                    m_strQueryParams = "?ctype=" + strCTID;
                    if (List != null)
                    {
                        m_strQueryParams += "&List=" + strListID;
                        m_ct =
                           List.ContentTypes[new SPContentTypeId(strCTID)];
                    }
                    else
                    {
                        m_ct =
                            Web.ContentTypes[new SPContentTypeId(strCTID)];
                        m_bContentTypeTemplate = true;
                    }
                }
                else
                    m_strQueryParams = "?List=" + strListID;
            }
    
            #endregion
    
            #region Form Data Serialization
    
            // Deserializes the association xml string and populates the
            // fields in the form.
            internal void PopulatePageFromXml(string associationXml,
                FormType type)
            {
                XmlSerializer serializer =
                    new XmlSerializer(typeof(FormData));
                XmlTextReader reader =
                    new XmlTextReader(
                        new System.IO.StringReader(associationXml));
                FormData formdata =
                    (FormData)serializer.Deserialize(reader);
    
                if (type == FormType.Association)
                {
                    textboxField1.Text = formdata.Field1;
                    textboxField2.Text = formdata.Field2;
                    textboxField3.Text = formdata.Field3;
                }
    
                textboxField4.Text = formdata.Field4;
                textboxField5.Text = formdata.Field5;
                textboxField6.Text = formdata.Field6;
            }
    
            // Serializes form data into an xml string to be passed into
            // the workflow.
            internal string SerializeFormToString(FormType type)
            {
                FormData data = new FormData();
    
                if (type == FormType.Association)
                {
                    data.Field1 = textboxField1.Text;
                    data.Field2 = textboxField2.Text;
                    data.Field3 = textboxField3.Text;
                }
    
                data.Field4 = textboxField4.Text;
                data.Field5 = textboxField5.Text;
                data.Field6 = textboxField6.Text;
    
                using (MemoryStream stream = new MemoryStream())
                {
                    XmlSerializer serializer =
                        new XmlSerializer(typeof(FormData));
                    serializer.Serialize(stream, data);
                    stream.Position = 0;
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    return Encoding.UTF8.GetString(bytes);
                }
            }
    
            #endregion
    
            #region Url Helper Functions
    
            public string strGroup = "Group";
            public string StrGetRelativeUrl(System.Web.UI.Page pgIn,
                string strPage, string strGrpName)
            {
                string strUrl = StrGetWebRelativePath(pgIn) + strPage;
                // No need to UrlEncodeAsUrl strUrl as it would have 
                // already been encoded.
                if (FValidString(strGrpName))
                    strUrl += "?" +
                        SPHttpUtility.UrlKeyValueEncode(strGroup) + "=" +
                        SPHttpUtility.UrlKeyValueEncode(strGrpName);
    
                return strUrl;
            }
            public string StrGetWebRelativePath(System.Web.UI.Page pgIn)
            {
                string strT = SPUtility.OriginalServerRelativeRequestUrl;
    
                int iLastSlash = strT.LastIndexOf("/");
                if (iLastSlash > 0)
                {
                    strT = SPHttpUtility.UrlPathEncode(
                            SPHttpUtility.UrlPathDecode(
                                strT, /*allowHashParameter*/ true),
                                /*allowHashParameter*/ true);
                    iLastSlash = strT.LastIndexOf("/");
                    return strT.Substring(0, iLastSlash + 1);
                }
                else
                    return string.Empty;
            }
            public bool FValidString(string strIn)
            {
                return FValidString(strIn, 2048);
            }
            public bool FValidString(string strIn, uint nMaxLength)
            {
                return (strIn != null && strIn.Length > 0 &&
                        strIn.Length <= nMaxLength);
            }
            #endregion
        }
    }
    
  6. Add the following code to the FormDataAssocForm.aspx file.

    <%-- _lcid="1033" _version="12.0.3208" _dal="1" --%>
    <%-- _LocalBinding --%>
    <%@ Assembly Name="FormDataAspxPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<Public Key Token>"%>
    <%@ Page Language="C#" EnableSessionState="true" ValidateRequest="False" Inherits="FormDataAspxPages.WFAssoc"
        MasterPageFile="~/_layouts/application.master"  %>
    <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %>    
    <%@ Register TagPrefix="wssuc" TagName="LinksTable" src="/_controltemplates/LinksTable.ascx" %> <%@ Register TagPrefix="wssuc" TagName="InputFormSection" src="/_controltemplates/InputFormSection.ascx" %> <%@ Register TagPrefix="wssuc" TagName="InputFormControl" src="/_controltemplates/InputFormControl.ascx" %> <%@ Register TagPrefix="wssuc" TagName="LinkSection" src="/_controltemplates/LinkSection.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ButtonSection" src="/_controltemplates/ButtonSection.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ActionBar" src="/_controltemplates/ActionBar.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ToolBar" src="/_controltemplates/ToolBar.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="/_controltemplates/ToolBarButton.ascx" %> <%@ Register TagPrefix="wssuc" TagName="Welcome" src="/_controltemplates/Welcome.ascx" %>
    <%@ Register Tagprefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="Workflow" Namespace="Microsoft.SharePoint.Workflow" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <script language="JavaScript">
        function _spBodyOnLoad()
        {
            try
            {
                window.focus();
            }
            catch(e)
            {
            }
        }
        function DoValidateAndSubmit()
        {
            return true;
        }
    </script>
    </asp:Content>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
        <asp:Literal ID="Literal1" runat="server" Text="Customize Workflow" />
    </asp:Content>
    
    <asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
        <%
            string strPTS = "Customize " + m_workflowName;
            SPHttpUtility.HtmlEncode(strPTS, Response.Output);
        %>
        :
        <asp:HyperLink ID="hlReturn" runat="server" />
    </asp:Content>
    
    <asp:Content ID="Content4" ContentPlaceHolderID="PlaceHolderPageImage" runat="server">
        <img src="/_layouts/images/blank.gif" width="1" height="1" alt="" />
    </asp:Content>
    
    <asp:Content ID="Content5" ContentPlaceHolderID="PlaceHolderPageDescription" runat="server">
        <%
            string strPD = "Use this page to customize this instance of " + m_workflowName + ".";
            SPHttpUtility.HtmlEncode(strPD, Response.Output);
        %>
    </asp:Content>
    
    <asp:Content ID="Content6" ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <asp:Table CellSpacing="0" CellPadding="0" BorderWidth="0" CssClass="ms-propertysheet">
            <wssuc:InputFormSection Title="Workflow Data Values" Description="Specify the default workflow data values." runat="server">
                <template_inputformcontrols>
                    <wssuc:InputFormControl Runat="server" LabelText="Specify Form Data Values:">
                        <Template_Control>
                            <table border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 1: <asp:TextBox id="textboxField1" runat="server"></asp:TextBox>
                                    </td>
                                </tr>
                                 <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 2: <asp:TextBox id="textboxField2" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>
                                 <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 3: <asp:TextBox id="textboxField3" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>
                                 <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 4: <asp:TextBox id="textboxField4" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>
                                 <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 5: <asp:TextBox id="textboxField5" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>
                                 <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 6: <asp:TextBox id="textboxField6" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>                     
                            </table>
    
    
                        </Template_Control>
                    </wssuc:InputFormControl>
                </template_inputformcontrols>
            </wssuc:InputFormSection>
    
            <input type="hidden" name="WorkflowDefinition" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["WorkflowDefinition"]),Response.Output); %>'/>
            <input type="hidden" name="WorkflowName" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["WorkflowName"]),Response.Output); %>'/>
            <input type="hidden" name="AddToStatusMenu" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AddToStatusMenu"]),Response.Output); %>'/>
            <input type="hidden" name="AllowManual" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AllowManual"]),Response.Output); %>'/>
            <input type="hidden" name="RoleSelect" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["RoleSelect"]),Response.Output); %>'/>
            <input type="hidden" name="GuidAssoc" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["GuidAssoc"]),Response.Output); %>'/>
            <input type="hidden" name="SetDefault" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["SetDefault"]),Response.Output); %>'/>
            <input type="hidden" name="HistoryList" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["HistoryList"]),Response.Output); %>'/>
            <input type="hidden" name="TaskList" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["TaskList"]),Response.Output); %>'/>
            <input type="hidden" name="UpdateLists" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["UpdateLists"]),Response.Output); %>'/>        
            <input type="hidden" name="AutoStartCreate" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AutoStartCreate"]),Response.Output); %>'/>
            <input type="hidden" name="AutoStartChange" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AutoStartChange"]),Response.Output); %>'/>
    
            <wssuc:ButtonSection runat="server">
                <template_buttons>
                    <asp:PlaceHolder runat="server">
                        <asp:Button runat="server" class="ms-ButtonHeightWidth" OnClick="BtnOK_Click" Text="OK" id="btnOK" />
                    </asp:PlaceHolder>
                </template_buttons>
            </wssuc:ButtonSection>
        </asp:Table>
    </asp:Content>
    
  7. Add the following code to the FormDataAssocForm.cs file.

    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.IO;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.Xml;
    
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Workflow;
    
    namespace FormDataAspxPages
    {
        public class WFAssoc : WFDataPages
        {
            protected string m_workflowName;
            protected bool m_allowManual;
            protected bool m_autoStartCreate;
            protected bool m_autoStartChange;
            protected Guid m_taskListId;
            protected string m_taskListName;
            protected Guid m_historyListId;
            protected string m_historyListName;
            protected bool m_setDefault;
            protected bool m_updateLists;
            protected bool m_bLockItem;
            protected SPWorkflowTemplate m_baseTemplate;
            protected SPWorkflowAssociation m_assocTemplate;
            protected HyperLink hlReturn;
    
            protected override void OnInit(EventArgs e)
            {
                base.OnInit(e);
            }
            protected override void OnPreRender(EventArgs e)
            {
                base.OnPreRender(e);
                if (m_assocTemplate != null)
                    PopulatePageFromXml(
                        (string)m_assocTemplate.AssociationData,
                        FormType.Association);
            }
            protected override void OnLoad(EventArgs ea)
            {
                base.OnLoad(ea);
    
                //Get the Workflow Name.
                m_workflowName = Request.Params["WorkflowName"];
    
                FetchAssociationInfo();
                GetTaskAndHistoryList();
            }
    
            #region Fetch Methods
    
            private void FetchAssociationInfo()
            {
                SPWorkflowAssociationCollection wac;
                m_baseTemplate = Web.WorkflowTemplates[new Guid(Request.Params["WorkflowDefinition"])];
                m_assocTemplate = null;
    
                // Determine whether or not this is associating with a
                // content type or a list, and get the association 
                // collection.  Also set the return page values.
    
                if (m_ct != null)
                {
                    // Associating with a content type.
                    wac = m_ct.WorkflowAssociations;
                    hlReturn.Text = m_ct.Name;
                    hlReturn.NavigateUrl = "ManageContentType.aspx" + m_strQueryParams;
                }
                else
                {
                    // Associating with a list.
                    List.CheckPermissions(SPBasePermissions.ManageLists);
    
                    wac = List.WorkflowAssociations;
                    hlReturn.Text = List.Title;
                    hlReturn.NavigateUrl = List.DefaultViewUrl;
                }
                if (wac == null || wac.Count < 0)
                {
                    throw new SPException("No Associations Found");
                }
                //Set the general workflow properties.
                m_autoStartCreate = (Request.Params["AutoStartCreate"] == "ON");
                m_autoStartChange = (Request.Params["AutoStartChange"] == "ON");
                m_allowManual = (Request.Params["AllowManual"] == "ON");
                m_bLockItem = (Request.Params["LockItem"] == "ON");
                m_setDefault = (Request.Params["SetDefault"] == "ON");
                m_updateLists = (Request.Params["UpdateLists"] == "TRUE");
    
                // Check if workflow association already exists.
                string strGuidAssoc = Request.Params["GuidAssoc"];
                if (strGuidAssoc != string.Empty)
                {
                    m_assocTemplate = wac[new Guid(strGuidAssoc)];
                }
    
                // Check for a duplicate name. Note that we do this both on initial load and on
                // postback. The reason we do it on postback is that some other user may have
                // added a workflow by the same name since the last time we checked.
                SPWorkflowAssociation dupTemplate = wac.GetAssociationByName(m_workflowName, Web.Locale);
    
                if (dupTemplate != null && (m_assocTemplate == null || m_assocTemplate.Id != dupTemplate.Id))
                {
                    // Throw an exception if there is already a template with the same name.
                    throw new SPException("Duplicate workflow name is detected.");
                }
            }
    
            private void GetTaskAndHistoryList()
            {
                if (m_bContentTypeTemplate)
                {
                    m_taskListName = Request.Params["TaskList"];
                    m_historyListName = Request.Params["HistoryList"];
                }
                else
                {
    
                    // If the user has requested that a new task or history list be created, check
                    // that the name does not duplicate the name of an existing list. If it does, show
                    // the user an appropriate error page.
    
                    string taskListGuid = Request.Params["TaskList"];
                    if (taskListGuid[0] != 'z') // already existing list
                    {
                        m_taskListId = new Guid(taskListGuid);
                    }
                    else  // new list
                    {
                        SPList list = null;
                        m_taskListName = taskListGuid.Substring(1);
                        try
                        {
                            list = Web.Lists[m_taskListName];
                        }
                        catch (ArgumentException)
                        {
                        }
    
                        if (list != null)
                            throw new SPException("A list already exists with the same name as that proposed for the new task list. Use your browser's Back button and either change the name of the workflow or select an existing task list.&lt;br&gt;");
                    }
    
                    // Do the same for the history list
                    string strHistoryListGuid = Request.Params["HistoryList"];
                    if (strHistoryListGuid[0] != 'z') // user selected already existing list
                    {
                        m_historyListId = new Guid(strHistoryListGuid);
                    }
                    else // User wanted a new list
                    {
                        SPList list = null;
    
                        m_historyListName = strHistoryListGuid.Substring(1);
    
                        try
                        {
                            list = Web.Lists[m_historyListName];
                        }
                        catch (ArgumentException)
                        {
                        }
                        if (list != null)
                            throw new SPException("A list already exists with the same name as that proposed for the new history list. Use your browser's Back button and either change the name of the workflow or select an existing history list.&lt;br&gt;");
                    }
                }
            }
    
            #endregion
    
            #region Button Click handlers
    
            public void BtnOK_Click(object sender, EventArgs e)
            {
                SPList taskList = null;
                SPList historyList = null;
                if (!IsValid)
                    return;
                if (!m_bContentTypeTemplate)
                {
                    // If the user requested a new task list, create it.
                    if (m_taskListId == Guid.Empty)
                    {
                        string description = string.Format("Task list for the {0} workflow.", m_workflowName);
                        m_taskListId = Web.Lists.Add(m_taskListName, description, SPListTemplateType.Tasks);
                    }
    
                    // If the user requested a new history list, create it.
                    if (m_historyListId == Guid.Empty)
                    {
                        string description = string.Format("History list for the {0} workflow.", m_workflowName);
                        m_historyListId = Web.Lists.Add(m_historyListName, description, SPListTemplateType.WorkflowHistory);
                    }
                    taskList = Web.Lists[m_taskListId];
                    historyList = Web.Lists[m_historyListId];
                }
    
                // Perform association (if it does not already exist).
                bool isNewAssociation;
                if (m_assocTemplate == null)
                {
                    isNewAssociation = true;
                    if (!m_bContentTypeTemplate)
                        m_assocTemplate = SPWorkflowAssociation.CreateListAssociation(m_baseTemplate,
                                                                      m_workflowName,
                                                                      taskList,
                                                                      historyList);
                    else
                    {
                        m_assocTemplate = SPWorkflowAssociation.CreateSiteContentTypeAssociation(m_baseTemplate,
                                                                      m_workflowName,
                                                                      m_taskListName,
                                                                      m_historyListName);
                    }
                }
                else // Modify existing template.
                {
                    isNewAssociation = false;
                    m_assocTemplate.Name = m_workflowName;
                    m_assocTemplate.SetTaskList(taskList);
                    m_assocTemplate.SetHistoryList(historyList);
                }
    
                // Set up startup parameters in the template.
                m_assocTemplate.Name = m_workflowName;
                m_assocTemplate.LockItem = m_bLockItem;
                m_assocTemplate.AutoStartCreate = m_autoStartCreate;
                m_assocTemplate.AutoStartChange = m_autoStartChange;
                m_assocTemplate.AllowManual = m_allowManual;
    
                if (m_assocTemplate.AllowManual)
                {
                    SPBasePermissions newPerms = SPBasePermissions.EmptyMask;
    
                    if (Request.Params["ManualPermEditItemRequired"] == "ON")
                        newPerms |= SPBasePermissions.EditListItems;
                    if (Request.Params["ManualPermManageListRequired"] == "ON")
                        newPerms |= SPBasePermissions.ManageLists;
    
                    m_assocTemplate.PermissionsManual = newPerms;
                }
    
                // Place data from form into the association template.
                m_assocTemplate.AssociationData = SerializeFormToString(FormType.Association);
    
                // If this is a content type association, add the template to the content type.
                if (m_ct != null)
                {
                    if (isNewAssociation)
                        m_ct.AddWorkflowAssociation(m_assocTemplate);
                    else
                        m_ct.UpdateWorkflowAssociation(m_assocTemplate);
                    if (m_updateLists)
                        m_ct.UpdateWorkflowAssociationsOnChildren(false);
                }
                else // Else, if this is a list association.
                {
                    if (isNewAssociation)
                        List.AddWorkflowAssociation(m_assocTemplate);
                    else
                        List.UpdateWorkflowAssociation(m_assocTemplate);
    
                    if (m_assocTemplate.AllowManual && List.EnableMinorVersions)
                    {
                        // If this WF was selected to be the content approval WF 
                        // (m_setDefault = true, see association page) then enable content
                        // Approval for the list.
                        if (List.DefaultContentApprovalWorkflowId != m_assocTemplate.Id && m_setDefault)
                        {
                            if (!List.EnableModeration)
                                List.EnableModeration = true;
                            List.DefaultContentApprovalWorkflowId = m_assocTemplate.Id;
                            List.Update();
                        }
                        else if (List.DefaultContentApprovalWorkflowId == m_assocTemplate.Id && !m_setDefault)
                        {
                            // Reset the DefaultContentApprovalWorkflowId
                            List.DefaultContentApprovalWorkflowId = Guid.Empty;
                            List.Update();
                        }
                    }
                }
    
                string strUrl = StrGetRelativeUrl(this, "WrkSetng.aspx", null) + m_strQueryParams;
                Response.Redirect(strUrl);
            }
    
            #endregion
        }
    }
    
  8. Add the following code to the FormDataInitForm.aspx file.

    <%-- _lcid="1033" _version="12.0.3208" _dal="1" --%>
    <%-- _LocalBinding --%>
    <%@ Assembly Name="FormDataAspxPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<Public Key Token>"%>
    <%@ Page Language="C#" EnableSessionState="true" ValidateRequest="False" Inherits="FormDataAspxPages.WFInit"
        MasterPageFile="~/_layouts/application.master"  %>
    <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %>    
    <%@ Register TagPrefix="wssuc" TagName="LinksTable" src="/_controltemplates/LinksTable.ascx" %> <%@ Register TagPrefix="wssuc" TagName="InputFormSection" src="/_controltemplates/InputFormSection.ascx" %> <%@ Register TagPrefix="wssuc" TagName="InputFormControl" src="/_controltemplates/InputFormControl.ascx" %> <%@ Register TagPrefix="wssuc" TagName="LinkSection" src="/_controltemplates/LinkSection.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ButtonSection" src="/_controltemplates/ButtonSection.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ActionBar" src="/_controltemplates/ActionBar.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ToolBar" src="/_controltemplates/ToolBar.ascx" %> <%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="/_controltemplates/ToolBarButton.ascx" %> <%@ Register TagPrefix="wssuc" TagName="Welcome" src="/_controltemplates/Welcome.ascx" %>
    <%@ Register Tagprefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="Workflow" Namespace="Microsoft.SharePoint.Workflow" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    
    <asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <script language="JavaScript">
        function _spBodyOnLoad()
        {
            try
            {
                window.focus();
            }
            catch(e)
            {
            }
        }
    </script>
    </asp:Content>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
        <asp:Literal ID="Literal1" runat="server" Text="Customize Workflow" />
    </asp:Content>
    
    <asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
        <%
            string strPTS = "Customize " + m_workflowName;
            SPHttpUtility.HtmlEncode(strPTS, Response.Output);
        %>
    </asp:Content>
    
    <asp:Content ID="Content4" ContentPlaceHolderID="PlaceHolderPageImage" runat="server">
        <img src="/_layouts/images/blank.gif" width="1" height="1" alt="" />
    </asp:Content>
    
    <asp:Content ID="Content5" ContentPlaceHolderID="PlaceHolderPageDescription" runat="server">
        <%
            string strPD = "Use this page to customize this instance of " + m_workflowName + ".";
            SPHttpUtility.HtmlEncode(strPD, Response.Output);
        %>
    </asp:Content>
    
    <asp:Content ID="Content6" ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <asp:Table CellSpacing="0" CellPadding="0" BorderWidth="0" CssClass="ms-propertysheet">
            <wssuc:InputFormSection Title="Workflow Data Values" Description="Specify the workflow data values." runat="server">
                <template_inputformcontrols>
                    <wssuc:InputFormControl LabelText="Specify Form Data Values:" runat="server">
                        <Template_Control>
                            <table border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 4: <asp:TextBox id="textboxField4" runat="server"></asp:TextBox>
                                    </td>
                                </tr>
                                <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 5: <asp:TextBox id="textboxField5" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>
                                 <tr>
                                    <td class="ms-authoringcontrols">
                                        Field 6: <asp:TextBox id="textboxField6" runat="server"></asp:TextBox>
                                    </td>
                                 </tr>
                            </table>
    
    
                        </Template_Control>
                    </wssuc:InputFormControl>
                </template_inputformcontrols>
            </wssuc:InputFormSection>
    
            <input type="hidden" name="WorkflowDefinition" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["WorkflowDefinition"]),Response.Output); %>'/>
            <input type="hidden" name="WorkflowName" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["WorkflowName"]),Response.Output); %>'/>
            <input type="hidden" name="AddToStatusMenu" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AddToStatusMenu"]),Response.Output); %>'/>
            <input type="hidden" name="AllowManual" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AllowManual"]),Response.Output); %>'/>
            <input type="hidden" name="RoleSelect" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["RoleSelect"]),Response.Output); %>'/>
            <input type="hidden" name="GuidAssoc" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["GuidAssoc"]),Response.Output); %>'/>
            <input type="hidden" name="SetDefault" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["SetDefault"]),Response.Output); %>'/>
            <input type="hidden" name="HistoryList" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["HistoryList"]),Response.Output); %>'/>
            <input type="hidden" name="TaskList" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["TaskList"]),Response.Output); %>'/>
            <input type="hidden" name="UpdateLists" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["UpdateLists"]),Response.Output); %>'/>        
            <input type="hidden" name="AutoStartCreate" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AutoStartCreate"]),Response.Output); %>'/>
            <input type="hidden" name="AutoStartChange" value='<% SPHttpUtility.NoEncode(SPHttpUtility.HtmlEncode(Request.Form["AutoStartChange"]),Response.Output); %>'/>
    
            <wssuc:ButtonSection runat="server">
                <template_buttons>
                    <asp:PlaceHolder runat="server">
                        <asp:Button runat="server" class="ms-ButtonHeightWidth" OnClick="BtnOK_Click" Text="OK" id="btnOK" />
                    </asp:PlaceHolder>
                </template_buttons>
            </wssuc:ButtonSection>
        </asp:Table>
    </asp:Content>
    
  9. Add the following code to the FormDataInitForm.cs file.

    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Text;
    using System.Collections;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.Xml;
    using System.Xml.Serialization;
    
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Workflow;
    
    namespace FormDataAspxPages
    {
        public class WFInit : WFDataPages
        {
            protected string m_workflowName;
            protected SPListItem m_listItem;
            protected string m_listItemName;
            protected string m_listItemUrl;
            protected SPWorkflowAssociation m_assocTemplate;
            protected SPWorkflowTemplate m_baseTemplate;
    
            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
    
                // Get the Workflow Name.
                m_workflowName = Request.Params["WorkflowName"];
    
                GetListItemInfo();
                GetAssociationInfo();
    
                if (!IsPostBack)
                {
                    PopulatePageFromXml((string)m_assocTemplate.AssociationData, FormType.Initiation);
                }
            }
    
            #region Fetch Methods
    
            private void GetAssociationInfo()
            {
                // Get ID of the association template
                Guid assocTemplateId = new Guid(Request.Params["TemplateID"]);
    
                // Fetch the association
                m_assocTemplate = List.WorkflowAssociations[assocTemplateId];
                if (m_assocTemplate == null) // its on a content type
                {
                    SPContentTypeId ctid = (SPContentTypeId)m_listItem["ContentTypeId"];
                    SPContentType ct = List.ContentTypes[ctid];
                    m_assocTemplate = ct.WorkflowAssociations[assocTemplateId];
                }
                // Make sure we found the association
                if (m_assocTemplate == null)
                    throw new SPException("The requested workflow could not be found.");
    
                // Get base template, workflow name, and form data
                m_baseTemplate = Web.WorkflowTemplates[m_assocTemplate.BaseId];
                m_workflowName = m_assocTemplate.Name;
                string m_formData = (string)m_assocTemplate.AssociationData;
            }
    
            private void GetListItemInfo()
            {
                // Get the item the workflow is being run on.
                m_listItem = List.GetItemById(Convert.ToInt32(Request.Params["ID"]));
    
                // Set the URL for workflow item.
                if (m_listItem.File == null)
                    m_listItemUrl = Web.Url + m_listItem.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].ServerRelativeUrl + "?ID=" + m_listItem.ID.ToString();
                else
                    m_listItemUrl = Web.Url + "/" + m_listItem.File.Url;
    
                // Set the list item name.
                if (List.BaseType == SPBaseType.DocumentLibrary)
                {
                    // If this is a document library, remove the extension of the file.
                    m_listItemName = (string)m_listItem["Name"];
                    int i = m_listItemName.LastIndexOf('.');
                    if (i > 0)
                        m_listItemName = m_listItemName.Substring(0, i);
                }
                else
                    m_listItemName = (string)m_listItem["Title"];
            }
    
            #endregion
    
            #region Button Click Handlers
            public void BtnOK_Click(object sender, EventArgs e)
            {
                string InitData = SerializeFormToString(FormType.Initiation);
                InitiateWorkflow(InitData);
            }
            #endregion
    
            private void InitiateWorkflow(string InitData)
            {
                try
                {
                    Web.Site.WorkflowManager.StartWorkflow(m_listItem, m_assocTemplate, InitData);
                }
                catch (Exception ex)
                {
                    SPException spEx = ex as SPException;
    
                    string errorString;
    
                    if (spEx != null && spEx.ErrorCode == -2130575205 /* SPErrorCode.TP_E_WORKFLOW_ALREADY_RUNNING */)
                        errorString = SPResource.GetString(Strings.WorkflowFailedAlreadyRunningMessage);
                    else if (spEx != null && spEx.ErrorCode == -2130575339 /* SPErrorCode.TP_E_VERSIONCONFLICT */)
                        errorString = SPResource.GetString(Strings.ListVersionMismatch);
                    else if (spEx != null && spEx.ErrorCode == -2130575338 /* SPErrorCode.TP_E_LISTITEMDELETED */)
                        errorString = spEx.Message;
                    else
                        errorString = SPResource.GetString(Strings.WorkflowFailedStartMessage);
    
                    SPUtility.Redirect("Error.aspx",
                        SPRedirectFlags.RelativeToLayoutsPage,
                        HttpContext.Current,
                        "ErrorText=" + SPHttpUtility.UrlKeyValueEncode(errorString));
                }
    
                SPUtility.Redirect(List.DefaultViewUrl, SPRedirectFlags.UseSource, HttpContext.Current);
            }
        }
    }
    
  10. Copy the FormData.cs file from the FormDataWorkflow project to the FormDataASPXPages project. In Solution Explorer, right-click the FormData.cs file and select Copy. Then right-click the FormDataASPXPages project and select Paste.

  11. Edit the copied FormData.cs file in the FormDataASPXPages project and change the namespace used from FormDataWorkflow to FormDataASPXPages.

  12. Build the FormDataASPXPages project. Visual Studio will display errors related to validation of the .aspx files. This occurs because Visual Studio is unable to locate the SharePoint application.master master page that is being referenced by the files. You can ignore these errors.

Strong Name Sign the Workflow Library and Form Assemblies

In order for the workflow library and ASPX form assemblies to be installed in the Global Assembly Cache they must be strong name signed. A strong name consists of the assembly's identity — it's simple text name, version number, and culture information (if provided) — plus a public key and a digital signature.

To assign a strong name to assemblies in Visual Studio

  1. Select the Project menu and then the <ProjectName> Properties menu item.

  2. On the project properties page, select the Signing tab.

  3. Select the Sign the assembly check box.

  4. In the Choose a strong name key file list, select <New...>.

  5. In the Create Strong Name Key dialog box, enter Keyfile as the key file name, and clear the Protect my key file with a password check box. n

  6. Close the project properties page.

  7. Build the workflow library and ASPX forms projects.

The code provided above for the FormDataAssocForm.aspx and FormDataInitForm.aspx pages uses the <Public Key Token> placeholder string for the Public Key Token attribute of the page Assembly directive. You must replace this placeholder string with the actual public key token of the FormDataASPXPages assembly. Use the Strong Name (sn.exe) utility that ships with .NET Framework Software Development Kit (SDK) to determine the public key token of the FormDataASPXPages assembly. To do this, open a Visual Studio 2005 command prompt and navigate to the folder that contains the assembly. Run sn.exe with the -T option against the assembly, in the following manner:

sn.exe -T FormDataASPXPages.dll

Make a note of the returned public key token and then edit the FormDataAssocForm.aspx and FormDataInitForm.aspx files, replacing the <Public Key Token> placeholder string with the token that is returned by sn.exe.

Deploy the Workflow

When Visual Studio created the FormDataWorkflow workflow project it created two deployment-related files: feature.xml and workflow.xml. Feature.xml defines the workflow as an installable SharePoint feature and workflow.xml defines the actual workflow. Initially, these files contain only instructions about how to insert the necessary code snippets to define the workflow feature and the workflow itself. To modify the feature.xml and workflow.xml files to work with the FormDataWorkFlow workflow, do the following:

To deploy the workflow

  1. Open the feature.xml file and replace its contents with the following markup.

    <?xml version="1.0" encoding="utf-8"?>
    <!-- _lcid="1033" _version="12.0.3111" _dal="1" -->
    <!-- _LocalBinding -->
    
    <Feature  Id="GUID"
              Title="Form Data Access Workflow"
              Description="This feature is a workflow that illustrates accessing workflow association initiation form data."
              Version="12.0.0.0"
              Scope="Site"
              xmlns="https://schemas.microsoft.com/sharepoint/">
      <ElementManifests>
        <ElementManifest Location="workflow.xml" />
      </ElementManifests>
      <Properties>
        <Property Key="GloballyAvailable" Value="true" />
      </Properties>
    </Feature>
    
  2. Replace the Feature Id attribute GUID placeholder with a unique GUID. A unique GUID can be easily generated from within Visual Studio by selecting Tools and then Create GUID, launching the Create GUID tool.

  3. In the Create GUID tool, choose the Registry Format and then select Copy to copy the GUID to the clipboard. Paste the GUID into the markup, replacing the GUID placeholder text. Do not include the opening and closing curly braces when adding the GUID to the Id attribute.

    Figure 9. Creating a GUID

    Create GUID

  4. Open the workflow.xml file and replace its contents with the following markup.

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- _lcid="1033" _version="12.0.3015" _dal="1"   -->
    <!-- _LocalBinding   -->
    
    <Elements xmlns="https://schemas.microsoft.com/sharepoint/">
      <Workflow
           Name="Form Data Access"
           Description="This workflow illustrates accessing association and initiation form data."
           Id="GUID"
           CodeBesideClass="FormDataWorkflow.Workflow1" 
           CodeBesideAssembly="FormDataWorkflow, Version=1.0.0.0, Culture=neutral, PublicKeyToken=publicKeyToken"
           AssociationUrl="_layouts/FormDataAssocForm.aspx"
           InstantiationUrl="_layouts/FormDataInitForm.aspx">
    
        <Categories/>
        <MetaData>
        </MetaData>
      </Workflow>
    </Elements>
    

    Use the process described above to replace the Workflow Id attribute GUID placeholder with a unique GUID.

  5. Save the changes to the feature.xml and workflow.xml files.

  6. To ease the deployment process, create a batch file called InstallAll.bat in the folder that contains the FormDataWorkflow.sln Visual Studio solution file. Add the following code to the InstallAll.bat file.

    iisreset /stop
    
    "%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -uf FormDataAspxPages
    "%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if FormDataASPXPages\bin\Debug\FormDataAspxPages.dll
    
    "%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -uf FormDataWorkflow
    "%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if FormDataWorkflow\bin\Debug\FormDataWorkflow.dll
    
    iisreset /start
    
    copy /Y "FormDataAspxPages\FormDataAssocForm.aspx" %SystemDrive%"\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"
    copy /Y "FormDataAspxPages\FormDataInitForm.aspx" %SystemDrive%"\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"
    
    mkdir  %SystemDrive%"\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES\FormDataWorkflow"
    
    copy "FormDataWorkflow\Feature.xml" %SystemDrive%"\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES\FormDataWorkflow"
    copy "FormDataWorkflow\workflow.xml" %SystemDrive%"\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES\FormDataWorkflow" 
    
    pushd "%programfiles%\common files\microsoft shared\web server extensions\12\bin"
    
    stsadm -o deactivatefeature -filename "FormDataWorkflow\feature.xml" -url https://localhost -force
    stsadm -o uninstallfeature -filename "FormDataWorkflow\feature.xml" -force
    
    stsadm -o installfeature -filename "FormDataWorkflow\feature.xml" -force
    stsadm -o activatefeature -filename "FormDataWorkflow\feature.xml" -url https://localhost -force
    
    popd
    
    PAUSE
    

    Build the FormDataWorkflow solution and then run the InstallAll.bat file to deploy the workflow. After the deployment has succeeded, you can associate the workflow with a SharePoint list, library, or content type and then test the association. For more information about how to associate a workflow with a list, library, or content type, refer to the Add or change a workflow for a list, library, or content type article on Microsoft Office Online.

Conclusion

This article illustrated how to access data from workflow association and initiation forms. The key steps include:

  • Creating a SharePoint Sequential Workflow Library project in Microsoft Visual Studio.

  • Designing the workflow outline using Visual Studio 2005 Designer for Windows Workflow Foundation.

  • Setting the properties of the workflow activities.

  • Adding code to the workflow that works with the data specified on the workflow association and initiation forms.

  • Adding a Class Library project to the solution that contains ASPX forms and supporting code files to implement the workflow association and initiation forms.

  • Strong name signing the workflow library and ASPX pages class library assemblies.

  • Deploying the workflow.

Additional Resources