Here in Part 4, we create the workflow and deploy it to the SharePoint server. I have done these steps with both Visual Studio 2005 and 2008. When deploying, it tells you what to do based on whether you are using 2005 or 2008. Also, I included VB as well as C# code depending on your tastes. It seems like most everybody is using C#. We use VB in-house traditionally so I figured I would stay with VB. You'll notice that there really isn't a whole lot of code here at all - just lots and lots of steps. This workflow works off of four states: InitialState, InitiatorApproval, PeerReviewerApproval and FinalState.
1. In Visual Studio 2005, File -> New -> Project -> SharePoint -> SharePoint Server State Machine, call it AgendaItemPeerReview
In Visual Studio 2008, File -> New -> Project -> Visual Basic -> Office -> 2007 -> SharePoint 2007 State Machine Workflow,
call it AgendaItemPeerReview
set location to d:\asp or whatever you want
Rename Workflow1.vb to PeerReviewWorkflow.vb and doubleclick it to open the design surface.
It will start out with a state called Workflow1InitialState. Rename Workflow1InitialState to InitialState.
Note: The workflow MUST have a different name than the solution/project. Do NOT rename file workflow1.cs (and thus the
workflow1 class) to the same name you chose as the solution/project.
2. add three more states and name them InitiatorApproval, PeerReviewerApproval and FinalState
3. right click workflow and set CompletedStateFinish property to the new state you created called FinalState
be sure InitialStateName is InitialState
We will build the workflow by adding activities to the various states.
Afterwards, we will come back and add the necessary code. I do it this way because some code is autogenerated while
other code must be written by us, and by building the whole workflow first, all the generated code will be together,
then all our code will be together below the generated code. Also, this provides more of a top-down approach to
designing (and understanding) the workflow.
4. in state InitialState, click eventDrivenActivity1 and rename it to InitialStateActivities
5. double-click this activity to drill down into it; in here we will create a sequential workflow; notice there is
already an onWorkflowActivated1 event
a. Rename onWorkflowActivated1 to onWorkflowActivated.
b. Drill down into CorrelationToken and change OwnerActivityName to PeerReviewWorkflow.
c. Drill down into WorkflowProperties and change Name to PeerReviewWorkflow.
6. in the Toolbox, find the Windows Workflow section and drag and drop a SetState event below onWorkflowActivated
a. rename setState activity to setStatePeerReviewerApproval
b. set TargetStateName property to PeerReviewerApproval
c. click on PeerReviewWorkflow to go back to workflow view; notice the line drawn from InitialState to
state PeerReviewerApproval
For the two approval states, we are going to add the same stuff, ie initialization code for when a state is entered,
code to execute while in the state, and code to execute when the state is completed.
7. for each of the two states, drag and drop into them:
a. a StateInitialization activity
b. an EventDriven activity
c. a StateFinalization activity
8. in stateInitiatorApproval, rename the activities to:
InitiatorApprovalInitialization
InitiatorApprovalActivities
InitiatorApprovalFinalization
9. in statePeerReviewerApproval, rename the activities to:
PeerReviewerApprovalInitialization
PeerReviewerApprovalActivities
PeerReviewerApprovalFinalization
We will now add the specific tasks within each of these three activities (initialization, activities, finalization) for each state.
Essentially, we will be creating sequential workflows within each of these activities.
10. in InitiatorApproval, double-click InitiatorApprovalInitialization to drill down into it
11. drag and drop a CreateTask activity and set the following properties:
a. rename it createInitiatorApprovalTask
b. set CorrelationToken to InitiatorApprovalToken; click the + next to it to set the OwnerActivityName to
InitiatorApproval
c. for TaskId, click the ellipses, click the "Bind to a new member" tab, remove the 1 from the end of the "New member name"
and click OK
d. follow the same step for TaskProperties
e. exit this sequential workflow view by clicking on PeerReviewWorkflow on the design surface
12. double-click InitiatorApprovalFinalization to drill down into it
13. drag and drop a CompleteTask activity and set the following properties:
a. rename it completeInitiatorApprovalTask
b. set CorrelationToken to InitiatorApprovalToken; click the + next to it to set the OwnerActivityName to
InitiatorApproval
c. for TaskId, click the ellipses, on the "Bind to an existing member" tab, click createInitiatorApprovalTask_TaskId
d. exit this sequential workflow view by clicking on PeerReviewWorkflow on the design surface
14. double-click InitiatorApprovalActivities to drill down into it
15. drag and drop an OnTaskChanged activity and set the following properties:
a. rename it onInitiatorApprovalChanged
b. set CorrelationToken to InitiatorApprovalToken; click the + next to it to set the OwnerActivityName to
InitiatorApproval
c. for TaskId, click the ellipses, on the "Bind to an existing member" tab, click createInitiatorApprovalTask_TaskId
d. for AfterProperties and BeforeProperties, click the ellipses, click the "Bind to a new member" tab,
remove the 1 from the end of the "New member name" and click OK
16. drag and drop an IfElse activity and rename it InitiatorApprovalStatus
17. click on the left branch and set the following properties:
a. rename it ifInitiatorApproved
b. for Condition, click Code Condition
18. drag and drop a setState activity under ifInitiatorApproved
a. rename it setStatePeerReviewerApproval
b. set the TargetStateName to PeerReviewerApproval
19. click PeerReviewWorkflow to go back to higher-level view of workflow
20. in PeerReviewerApproval, double-click PeerReviewerApprovalInitialization to drill down into it
21. drag and drop a CreateTask activity and set the following properties:
a. rename it createPeerReviewerApprovalTask
b. set CorrelationToken to PeerReviewerApprovalToken; click the + next to it to set the OwnerActivityName to
PeerReviewerApproval
c. for TaskId, click the ellipses, click the "Bind to a new member" tab, remove the 1 from the end of the "New member name"
and click OK
d. follow the same step for TaskProperties
e. exit this sequential workflow view by clicking on PeerReviewWorkflow on the design surface
22. double-click PeerReviewerApprovalFinalization to drill down into it
23. drag and drop a CompleteTask activity and set the following properties:
a. rename it completePeerReviewerApprovalTask
b. set CorrelationToken to PeerReviewerApprovalToken; click the + next to it to set the OwnerActivityName to
PeerReviewerApproval
c. for TaskId, click the ellipses, on the "Bind to an existing member" tab, click createPeerReviewerApprovalTask_TaskId
d. exit this sequential workflow view by clicking on PeerReviewWorkflow on the design surface
24. double-click PeerReviewerApprovalActivities to drill down into it
25. drag and drop an OnTaskChanged activity and set the following properties:
a. rename it onPeerReviewerApprovalChanged
b. set CorrelationToken to PeerReviewerApprovalToken; click the + next to it to set the OwnerActivityName to
InitiatorApproval
c. for TaskId, click the ellipses, on the "Bind to an existing member" tab, click createPeerReviewerApprovalTask_TaskId
d. for AfterProperties and BeforeProperties, click the ellipses, click the "Bind to a new member" tab,
remove the 1 from the end of the "New member name" and click OK
26. drag and drop an IfElse activity and rename it PeerReviewerApprovalStatus
27. click on the left branch and set the following properties:
a. rename it ifPeerReviewerApproved
b. for Condition, click Code Condition
28. drag and drop a setState activity under ifPeerReviewerApproved
a. rename it setStateFinalState
b. set the TargetStateName to FinalState
29. click on the right branch and set the following properties:
a. rename it ifPeerReviewerRejected
b. for Condition, click Code Condition
30. drag and drop a setState activity under ifPeerReviewerRejected
a. rename it setStateInitiatorApproval
b. set the TargetStateName to InitiatorApproval
Now we are ready to start adding code. First we will add code in InitialState, for when the workflow starts.
31. Go to the code-behind and find the following line (this is the VB version, but the C# version looks almost identical):
Public workflowProperties As SPWorkflowActivationProperties = New Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties
Above it, type:
VISUAL BASIC
------------
Public workflowId As System.Guid
VISUAL C#
---------
public Guid workflowId = default(System.Guid);
Below the workflowProperties line, type:
VISUAL BASIC
------------
Dim PeerReviewer As String
Dim CC As String
Dim Instructions As String
VISUAL C#
---------
private String PeerReviewer = default(String);
private String CC = default(String);
private String Instructions = default(String);
32. back on design surface, double-click InitialStateActivitites to drill down into it
33. double-click onWorkflowActivated. This will take you to the code behind and show the generated code stub
onWorkflowActivated_Invoked. Copy and paste the following code into it:
VISUAL BASIC
------------
workflowId = workflowProperties.WorkflowId
Dim serializer As XmlSerializer = New XmlSerializer(GetType(InitForm))
Dim reader As XmlTextReader = New XmlTextReader(New System.IO.StringReader(workflowProperties.InitiationData))
Dim initform As InitForm = CType(serializer.Deserialize(reader), InitForm)
Dim prPeerReviewer() As Person
prPeerReviewer = initform.gpPeerReviewer
PeerReviewer = prPeerReviewer(0).AccountId
Dim prCC() As Person
prCC = initform.gpCC
CC = prCC(0).AccountId
Instructions = initform.txtInstructions
VISUAL C#
---------
workflowId = workflowProperties.WorkflowId;
XmlSerializer serializer = new XmlSerializer(typeof(InitForm));
XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(workflowProperties.InitiationData));
InitForm initform = (InitForm)serializer.Deserialize(reader);
Person prPeerReviewer = new Person();
prPeerReviewer = (Person)initform.gpPeerReviewer[0];
//PeerReviewer = prPeerReviewer.AccountId.GetValue(0).ToString();
PeerReviewer = prPeerReviewer.AccountId;
Person prCC = new Person();
prCC = (Person)initform.gpCC[0];
//CC = prCC.AccountId.GetValue(0).ToString();
CC = prCC.AccountId;
Instructions = initform.txtInstructions;
34. go to the top of PeerReviewWorkflow.vb and add the following code:
VISUAL BASIC
------------
imports System.Xml.Serialization
imports System.Xml
VISUAL C#
---------
using System.Xml.Serialization;
using System.Xml;
Next, we will add code to the InitiatorApproval state.
35. go back to the design surface and double-click InitiatorApprovalInitialization to drill down into it
36. double-click createInitiatorApprovalTask to be taken to its MethodInvoking code stub. Copy and paste
the following code in it.
VISUAL BASIC
------------
createInitiatorApprovalTask_TaskId = Guid.NewGuid
createInitiatorApprovalTask_TaskProperties = new SPWorkflowTaskProperties
createInitiatorApprovalTask_TaskProperties.Title = "Initiator Approval of " & workflowProperties.Item.File.Name
createInitiatorApprovalTask_TaskProperties.AssignedTo = workflowProperties.Originator
createInitiatorApprovalTask_TaskProperties.Description = ""
createInitiatorApprovalTask_TaskProperties.TaskType = 0
createInitiatorApprovalTask_TaskProperties.ExtendedProperties("txtInstructions") = Instructions
VISUAL C#
---------
createInitiatorApprovalTask_TaskId = Guid.NewGuid();
createInitiatorApprovalTask_TaskProperties = new SPWorkflowTaskProperties();
createInitiatorApprovalTask_TaskProperties.Title = "Initiator Approval of " + workflowProperties.Item.File.Name;
createInitiatorApprovalTask_TaskProperties.AssignedTo = workflowProperties.Originator;
createInitiatorApprovalTask_TaskProperties.Description = "";
createInitiatorApprovalTask_TaskProperties.TaskType = 0;
createInitiatorApprovalTask_TaskProperties.ExtendedProperties["txtInstructions"] = Instructions;
37. go back to the design surface and double-click InitiatorApprovalActivities to drill down into it
38. double-click onInitiatorApprovalChanged to be taken to its Invoked code stub. Copy and paste
the following code in it.
VISUAL BASIC
------------
onInitiatorApprovalChanged_AfterProperties = onInitiatorApprovalChanged.AfterProperties
onInitiatorApprovalChanged_BeforeProperties = onInitiatorApprovalChanged.BeforeProperties
VISUAL C#
---------
onInitiatorApprovalChanged_AfterProperties = onInitiatorApprovalChanged.AfterProperties;
onInitiatorApprovalChanged_BeforeProperties = onInitiatorApprovalChanged.BeforeProperties;
39. go back to the design surface and click ifInitiatorApproved and set the following properties:
a. drill down into the Condition property (already set to Code Condition), and next to the second
Condition property, type InitiatorApproved and hit enter
b. you will be taken to the code stub for InitiatorApproved routine; copy and paste the following
code into it:
VISUAL BASIC
------------
If onInitiatorApprovalChanged_AfterProperties.ExtendedProperties("status").ToString = "accepted" Then
e.Result = True
End If
VISUAL C#
---------
if (onInitiatorApprovalChanged_AfterProperties.ExtendedProperties["status"].ToString() == "accepted")
{
e.Result = true;
}
Next, we will add code to the PeerReviewerApproval state.
40. go back to the design surface and double-click PeerReviewerApprovalInitialization to drill down into it
41. double-click createPeerReviewerApprovalTask to be taken to its MethodInvoking code stub. Copy and paste
the following code in it.
VISUAL BASIC
------------
createPeerReviewerApprovalTask_TaskId = Guid.NewGuid
createPeerReviewerApprovalTask_TaskProperties = new SPWorkflowTaskProperties
createPeerReviewerApprovalTask_TaskProperties.Title = "Peer Reviewer Approval of " & workflowProperties.Item.File.Name
createPeerReviewerApprovalTask_TaskProperties.AssignedTo = PeerReviewer
createPeerReviewerApprovalTask_TaskProperties.Description = ""
createPeerReviewerApprovalTask_TaskProperties.TaskType = 0
createPeerReviewerApprovalTask_TaskProperties.ExtendedProperties("txtInstructions") = Instructions
VISUAL C#
---------
createPeerReviewerApprovalTask_TaskId = Guid.NewGuid();
createPeerReviewerApprovalTask_TaskProperties = new SPWorkflowTaskProperties();
createPeerReviewerApprovalTask_TaskProperties.Title = "Peer Reviewer Approval of " + workflowProperties.Item.File.Name;
createPeerReviewerApprovalTask_TaskProperties.AssignedTo = PeerReviewer;
createPeerReviewerApprovalTask_TaskProperties.Description = "";
createPeerReviewerApprovalTask_TaskProperties.TaskType = 0;
createInitiatorApprovalTask_TaskProperties.ExtendedProperties["txtInstructions"] = Instructions;
42. go back to the design surface and double-click PeerReviewerApprovalActivities to drill down into it
43. double-click onPeerReviewerApprovalChanged to be taken to its Invoked code stub. Copy and paste
the following code in it.
VISUAL BASIC
------------
onPeerReviewerApprovalChanged_AfterProperties = onPeerReviewerApprovalChanged.AfterProperties
onPeerReviewerApprovalChanged_BeforeProperties = onPeerReviewerApprovalChanged.BeforeProperties
VISUAL C#
---------
onPeerReviewerApprovalChanged_AfterProperties = onPeerReviewerApprovalChanged.AfterProperties;
onPeerReviewerApprovalChanged_BeforeProperties = onPeerReviewerApprovalChanged.BeforeProperties;
44. go back to the design surface and click ifPeerReviewerApproved and set the following properties:
a. drill down into the Condition property (already set to Code Condition), and next to the second
Condition property, type PeerReviewerApproved and hit enter
b. you will be taken to the code stub for PeerReviewerApproved routine; copy and paste the following
code into it:
VISUAL BASIC
------------
If onPeerReviewerApprovalChanged_AfterProperties.ExtendedProperties("status").ToString = "accepted" Then
e.Result = True
End If
VISUAL C#
---------
if (onPeerReviewerApprovalChanged_AfterProperties.ExtendedProperties["status"].ToString() == "accepted")
{
e.Result = true;
}
45. go back to the design surface and click ifPeerReviewerRejected and set the following properties:
a. drill down into the Condition property (already set to Code Condition), and next to the second
Condition property, type PeerReviewerRejected and hit enter
b. you will be taken to the code stub for PeerReviewerApproved routine; copy and paste the following
code into it:
VISUAL BASIC
------------
If onPeerReviewerApprovalChanged_AfterProperties.ExtendedProperties("status").ToString = "rejected" Then
e.Result = True
End If
VISUAL C#
---------
if (onPeerReviewerApprovalChanged_AfterProperties.ExtendedProperties["status"].ToString() == "rejected")
{
e.Result = true;
}
46. sign the assembly
a. right-click the project, then click properties
b. click Signing
c. if Sign the assembly is not already checked...
d. check Sign the assembly
e. choose <new> from the dropdown
f. enter MyKeyFile for the key file name
g. uncheck Protect my key file with a password
h. click OK
47. follow instructions above for creating the workflow's Initiation and Task forms using Microsoft Office InfoPath
48. If developing in Visual Studio 2005: copy PeerReviewInit.xsn and PeerReviewTask.xsn to DeploymentFiles\FeatureFiles folder
49. be sure feature.xml is set up correctly
a. title: Agenda Item Peer Review feature
b. description: This feature installs the Agenda Item Peer Review workflow
c. if deploying via Visual Studio 2008:
under the <ElementManifests> tag, add:
<ElementFile Location="PeerReviewInit.xsn" />
<ElementFile Location="PeerReviewTask.xsn" />
50. be sure workflow.xml is set up correctly
a. name: AgendaItemPeerReview
b. description: This is the Agenda Item Peer Review workflow
c. CodeBesideClass: AgendaItemPeerReview.PeerReviewWorkflow
d. after CodeBesideAssembly, you must have the following:
TaskListContentTypeId="0x01080100C9C9515DE4E24001905074F980F93160"
e. after TaskListContentTypeId, you must have the following:
AssociationUrl="_layouts/CstWrkflIP.aspx"
InstantiationUrl="_layouts/IniWrkflIP.aspx"
ModificationUrl="_layouts/ModWrkflIP.aspx"
f. copy initiation form's urn into the <Association_FormURN> and <Instantiation_FormURN> tags
g. copy task form's urn into the <Task0_FormURN> tag
51. deploy solution
a. Visual Studio 2005: right click project, click Properties, click Build Events, change NODEPLOY to
DEPLOY at the end of the Post-build event command line, click Build, click Rebuild Solution
b. Visual Studio 2008: click Build, then click Deploy Solution
52. The first time you deploy it, the AgendaItemPeerReview assembly is added to the GAC. The workflow.xml
file needs the assembly's public key token.
a. Start, Settings, Control Panel, Administrative Tools, Microsoft .NET Framework 2.0 Configuration
b. click Manage the Assembly Cache
c. click View List of Assemblies in the Assembly Cache
d. right-click on AgendaItemPeerReview and click Properties
e. copy the public key token and click OK
f. paste the public key token in workflow.xml where you find PublicKeyToken
g. redeploy solution (step 51)
Another method for retrieving the assembly's public key token
-------------------------------------------------------------
If you want to skip step 52, retrieve the public key token using the sn.exe utility then
update workflow.xml (step 50) with it
1. copy sn.exe from c:\program files\microsoft visual studio 8\sdk\v2.0\bin to d:\
2. change directory to d:\asp\agendaitempeerreview\agendaitempeerreview\bin\debug
3. d:\sn -T agendaitempeerreview.dll
4. copy (or type) the resulting public key token into the workflow.xml
Posts in this series:
Part 1: IntroductionPart 2: Create the initiation formPart 3: Create the task formPart 4: Create the state machine workflowPart 5: Add workflow history loggingPart 6: Add task notification emails