Table of Contents for on SharePoint 2007 WF Authoring using Visual studio.
1. Setting up your environment for writing VS2005 workflows.
2. Writing an ultra basic workflow, deploying it, and slicing dicing how it worked.
3. Making that workflow more complex, adding if/else, and a bunch of activities that sort of make it more interesting.
4. Adding user interaction to that workflow using Infopath forms.
5. Authoring SharePoint 2007 Workflows using VS2008.
In my first post about writing workflows for SharePoint 2007, I talked about setting up your environment. Once your environment is setup, I used the example of writing an ultra basic workflow, basically the equivalent of Roll Of Dice, the workflow has a single code activitiy, and uses workflowProperties to update the List Item's title.
Read the ultra basic workflow before reading this blogpost.
In writing that blogpost, I demonstrated the basic concepts of authoring workflows for sharepoint using the templates provided by Microsoft. I demonstrated how and where you would write your code, drop your or inbuilt activities, and how does deploying work in both debug and production environments, how the whole thing gets packaged up as a feature, a solution etc. It was a good introduction, but I seriously don't think that will be the typical business problem you will face.
In this blogpost, I am going to enhance that same example (so read the ultra basic WF first), and add some branching logic to it.
Basically, what I am going to do is, lets say I roll dice. Great! If I get anything over 3, I should win a prize. When that prize is created, the player has a task created for him, informing him that he needs to claim a prize.
Let us begin writing it then.
In order to introduce this enhancement to our WF, the steps are pretty simple.
- Think, logically, how my WF will change, and what new activities will I have to drop on the surface of the WF Designer.
- Once you create the skeleton of the WF, fill it's bones with some flesh - write the code-behind for it.
- Deploy, Run, Debug, Enjoy!
Here goes -
How will my WF change?
Okay, my WF currently looks like this -
Hmm .. so "if" <dice rolled > 3> - create task & inform the winner. So my WF should now look like this -
Don't worry about the red exclamation marks. We will take care of them next.
Also note, I didn't include a "sendEmail" activity. The dude can be informed, thanks to the createTask activity.
Write the code for the WF
Excellent. Now lets get rid of those checkboxes, and write the code for the various activities we dropped.
First, the rolled dice will now have to be accessible all through the workflow. So go ahead and modify the codeActivity1_ExecuteCode method to as below -
private Int32 diceValue= 0;
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
Random rnd = new Random() ;
diceValue = rnd.Next(1, 6);
workflowProperties.Item["Title"] = diceValue;
Now that the diceValue is a private variable, go ahead and hover over the red checkmark at the IfElseBranchActivity. It should tell you that the Condition is not set. Go ahead and click on it, and set a "Declarative Rule Condition" (simpler) inside of the properties dialog for the IfElseBranchActivity. Expand that tree view for "Condition", and click the ellipses by the "Condition Expression", and specify a condition as shown below:
You would note that you have full intellisense here. very nice!
The next step is to give flesh to the bones of the createTask1 activity. This is a tad bit tricky. Just tricky, not scary.
First of all, when you hover over the red checkmark by createTaskActivity, it tells you that correlationToken isn't set. CorrelationTokens are an interesting animal. The way a workflow works is that, only a single instance of the workflow is created by the WF host. All running instances of that workflow share that instance. This has serious implications of how workflows work (think threading). But I am not going to dive into the threading aspects of WF's in this blogpost, and leave that bitchfest for another post. Over here, what you've gotta consider is, how the hell does WF keep the WF straight, if multiple WF instances, share the same WF instance? The answer is, by using CorrelationTokens.
CorrelationTokens is what will let the WF host identify, what activity wants to do what in which workflow.
There are 3 kinds of CorrelationTokens - WorkfFlow, Task, and Modification Correlation Tokens.
Workflow Tokens will apply to the following activities - OnWorkflowActivated, OnWorkflowItemChanged, OnWorkflowItemDeleted, SetState, SendEmail and UpdateAllTasks.
Task Tokens will apply to the following activities - CreateTask, CreateTaskWithContentType, UpdateTask, DeleteTask, CompleteTask, RollBackTask, OnTaskChanged, OnTaskDeleted and OnTaskCreated.
Modification Tokens will apply to the following activities - EnableWorkflowModification, OnWorkflowModified.
So in our case, we have a createTask activitiy, which means, we need to create a NEW correlation token, that applies to Tasks. This ensures that subsequent activities can find that task and act upon it. In order to do so, go to the properties of the createTask1 Activity, and set the correlation token to "taskToken". DoNot pick workflowToken as prompted by the drop down. Also set the OwnerActivityName to any parent - I choose Workflow1 (whoaa, a workflow is an activity? yep!).
The next thing to do with createTaskActivity is frankly a tad bit annoying. Double click on the createTaskActivity and it will create a createTask1_MethodInvoking for you. It will also set the createTask1.MethodInvoking property appropriately.
Now what we need to do in the MethodInvoking property, is to set the TaskID (which is a GUID), and TaskProperties. In order to do so, first you need to create two new Fields (not DependencyProperties), that you will use for TaskID and TaskProperties. You can use the following steps to acheive this.
1. Back in WF Designer, right click, properties on the createTask1 activity.
2. In the Properties, click on the ellipsis by TaskID, and go to he Bind to a New Member Tab. Fill in the form as shown below.
3. Repeat the same for TaskProperties, make sure it is bound to a new Field called "createTask1_TaskProperties1"
Perfect. Now with these two fields setup, go ahead and modify the code for createTask1_MethodInvoking to as below:
private void createTask1_MethodInvoking(object sender, EventArgs e)
createTask1_TaskId1 = Guid.NewGuid();
createTask1_TaskProperties1.AssignedTo = workflowProperties.Originator;
createTask1_TaskProperties1.Title = "Congratulations, thou art ye winner!";
createTask1_TaskProperties1.Description = "You have won!!! Now go and claim your prize";
createTask1_TaskProperties1.SendEmailNotification = true;
As you can see, I am using the createTask Activity to send the email to the user. So I don't need to worry about a sendEmail activity.
So, That's it !
Deploy, Run, Debug, Enjoy!
Now, I have already covered Deploy, Run, Debug, in my previous blogpost, so I won't waste too much breath on that here. So let us dive straight into "Enjoy".
- Create a new list.
- Go to List settings, and associate an instance of the Roll Of Dice workflow to that list.
- Add an item in there
- Run the workflow you created in #2 above.
Now when I "win", i.e. get a value > 3, here is what I get for my Task -
and here is how the task email looks like in Outlook 2007 -
I would recommend that you play around with a few other activities, and complicate this WF even further.
You would very shortly note that, frequently, a WF will need to talk to the end user. Ask him for feedback, intial data, maybe even let the user modify a WF. How in the world are we supposed to handle that?
Well, by creating input forms that work with the Workflow. But that's for the next blogpost.