Programmatically setting up Approval workflow in MOSS

Out-of-box Approval works pretty well for simple content approval and that’s what exactly I wanted. If you attach an Approval workflow to a list from the UI you get number of options to set such as Approvers, People who needs to be notified and an important one if you want to update the approval status of a list item to Approved or Rejected is “Update the approval status (use this workflow to control content approval)” in “Post completion Workflow Activities”

As in most the real world situation I want to set this up during deployment process and not from the UI.

Following code snippet will set up your list with Moderation enabled:

SPList list = web.Lists["MyList"];
list.EnableModeration = true;
list.Update();

Following code snippet sets up the Approval work flow on the list

SPWorkflowTemplate baseTemplate = web.WorkflowTemplates.GetTemplateByName("Approval", CultureInfo.InvariantCulture);
SPWorkflowAssociation assoc = SPWorkflowAssociation.CreateListAssociation(baseTemplate, "Property Approval", web.Lists["Workflow Tasks"], web.Lists["Workflow History"]);
assoc.AllowManual = true;
assoc.AutoStartCreate = true;
string data = GetApprovalWorkFlowData();
assoc.AssociationData = data;
list.AddWorkflowAssociation(assoc);

In Above code snippet AssociationData property of SPWorkflowAssociation can be used to set things like Approvers, People who needs to be notified and “Post completion Workflow Activities” for content approval

AssociationData is in XML format and looks like:

<my:myFields xml:lang="en-us" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD">
  <my:Reviewers>
    <my:Person>
      <my:DisplayName>Ketul Patel</my:DisplayName>
      <my:AccountId>domain\kpatel</my:AccountId>
      <my:AccountType>User</my:AccountType>
    </my:Person>
  </my:Reviewers>
  <my:CC>
    <my:Person>
      <my:DisplayName>Joe Doe</my:DisplayName>
      <my:AccountId>domain\jdoe</my:AccountId>
      <my:AccountType>User</my:AccountType>
    </my:Person>
  </my:CC>
  <my:DueDate xsi:nil="true"></my:DueDate>
  <my:Description>A new Property has been added to the system and requires approval.</my:Description>
  <my:Title></my:Title>
  <my:DefaultTaskType>1</my:DefaultTaskType>
  <my:CreateTasksInSerial>true</my:CreateTasksInSerial>
  <my:AllowDelegation>true</my:AllowDelegation>
  <my:AllowChangeRequests>true</my:AllowChangeRequests>
  <my:StopOnAnyReject xsi:nil="true"></my:StopOnAnyReject>
  <my:WantedTasks xsi:nil="true"></my:WantedTasks>
  <my:SetMetadataOnSuccess>false</my:SetMetadataOnSuccess>
  <my:MetadataSuccessField></my:MetadataSuccessField>
  <my:MetadataSuccessValue></my:MetadataSuccessValue>
  <my:ApproveWhenComplete>true</my:ApproveWhenComplete>
  <my:TimePerTaskVal xsi:nil="true"></my:TimePerTaskVal>
  <my:TimePerTaskType xsi:nil="true"></my:TimePerTaskType>
  <my:Voting>false</my:Voting>
  <my:MetadataTriggerField></my:MetadataTriggerField>
  <my:MetadataTriggerValue></my:MetadataTriggerValue>
  <my:InitLock>false</my:InitLock>
  <my:MetadataStop>false</my:MetadataStop>
  <my:ItemChangeStop>false</my:ItemChangeStop>
  <my:GroupTasks>false</my:GroupTasks>
</my:myFields>

Various elements in the above XML are pretty self explaining and roughly maps to relevant tick box or textbox on the “Customize Workflow” Page (CstWrkflIP.aspx)

<my:ApproveWhenComplete>true</my:ApproveWhenComplete>

Is the element to use to set the “Update the approval status (use this workflow to control content approval)” checkbox

Advertisements

16 thoughts on “Programmatically setting up Approval workflow in MOSS

  1. Big, You can write a Feature receiver and deploy it on Feature Activation, google for Feature Receivers if you are not familiar with feature framework

    If your question is when the set-up code is executed than it can be executed when you activate the Feature

  2. How would you change the AssociationData for each time the workflow needs to start?

    I need to figure out the list of approvers at run time.
    Also doesn’t need to be ?

    • Sorry the format is messaed up

      Our Work flow accociation data looks like:

      {0}
      {1}
      User

      {2}

      1
      true
      true
      true

      false

      false

      false

      false
      false
      false
      false

      If you notice under it has {0} tokens, which gets replaced by actual user that was selected at run time, in ItemAdded Event see the code below:

      SPWorkflowAssociation wrkFl = list.WorkflowAssociations[0];

      string description = "'{0}' has applied for a new Holiday Request from '{1}' till '{2}' as a \"{3}\".\r\nDescription: {4}";

      SPFieldUserValue employee = new SPFieldUserValue(properties.Web, listItem[HRConstants.EmployeeNameField].ToString());

      description = String.Format(description, employee.User.Name
      , DateTime.Parse(listItem[HRConstants.LeaveStartDateField].ToString()).ToString()
      , DateTime.Parse(listItem[HRConstants.LeaveEndDateField].ToString()).ToString()
      , listItem[HRConstants.LeaveTypeField].ToString()
      , listItem[HRConstants.DescriptionField] != null ? listItem[HRConstants.DescriptionField].ToString() : string.Empty);

      SPFieldUserValue manager = new SPFieldUserValue(properties.Web, listItem[HRConstants.ReportsToField].ToString());

      //This line replaces the tokens in associationdata with manager's username
      string associationData = String.Format(wrkFl.AssociationData, manager.User.Name, SPClaimProviderManager.Local.DecodeClaim(manager.User.LoginName).Value, description);

      site.WorkflowManager.StartWorkflow(properties.ListItem, wrkFl, associationData, SPWorkflowRunOptions.Synchronous);

      • No not via SPD, we had the workflow association data with {0}’s {1}’s stored in an XML file and in a feature receiver the association data was read from the file as a string and assigned to the workflow association, and {0}’s {1}’s were replaced in Item Added event and workflow was started after replacing the tokens

      • Cool trick 🙂
        any chance you can send the file to ofer.gal@mpspartners.com ?

        I still get error “Coercion Failed: Input cannot be null for this coercion.” with my associationData and I can’t figure out which Input is the one causeing it

        Thanks in advance

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s