Your SlideShare is downloading. ×
Tutorial Share Point Happy Birthday Workflow Slideshare
Upcoming SlideShare
Loading in...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Tutorial Share Point Happy Birthday Workflow Slideshare


Published on

Tutorial on creating a SharePoint workflow that sends a Happy Birthday card (as a content type) that is paritally populated using an InfoPath form. It is then emailed to the recipient of the card. …

Tutorial on creating a SharePoint workflow that sends a Happy Birthday card (as a content type) that is paritally populated using an InfoPath form. It is then emailed to the recipient of the card. The interesting part is the disabling of the InfoPath form once the workflow is completed by using a secondary data source.

Published in: Technology

  • Be the first to comment

  • Be the first to like this

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide


  • 1. SlideShare.comSeptember 2009Tutorial – Coding a SharePoint Happy Birthday Workflow with Visual Studio 2008Using an InfoPath Form for Input and Word Document as OutputGeorge Catrombon
    This tutorial will demonstrate how to create a SharePoint sequential workflow that will reveal many useful techniques that can be applied in the field. The purpose of this workflow is to send a Birthday Card (as a Word document) via Email to a SharePoint user with some of the text of the Birthday Card filled out dynamically in C# code during the workflow. The dynamically populated fields will get their input from an InfoPath form presented to the person who is assigned the task of signing the card. This is similar to what might happen in an office today when your supervisor wants a person in his/her group to send a birthday card to a particular birthday boy or girl. In our situation, the supervisor creates the card from a SharePoint library as a Word document (as a content type) which has a workflow attached to it. The difference here is that the process is under the management of the workflow which we will code in Visual Studio 2008.
    Note: This is a long tutorial with a vast number of steps required to complete it. The reader should be alert to how complex the process is to create a very simple sequential workflow that does some fancy work behind the scenes using InfoPath forms.
    Let’s take a moment to better describe what we want. A birthday card will be created as a content type for a SharePoint library that we will create. We will call the library Happy Birthday Card Library. A birthday card will be a Word document, with a picture of a birthday cake, and several pre-defined fields as Word properties which are linked to column types in the library. Some of these fields will be filled out by the initiator of the birthday card (the supervisor most likely) which will include the name of the recipient (E.g. “Jane Smith”), an opening greeting (E.g. “Best wishes on your Birthday!”), the email address of the recipient, and the login name of the person assigned the task of signing the card (E.g. There will then be two additional fields which need to be populated by the signer of the card. These two fields are filled out by using an InfoPath form. These fields are from (E.g. “John”) and the message the signer would like to include (E.g. “Hope you like the cake!”). When the signer completes the workflow task, the workflow will finish populating the Word document Birthday Card with the two fields obtained from the InfoPath form, and then email the updated Birthday Card to the recipient as an email attachment. The workflow will then mark the task as completed. The other thing we will do is disable the submit button on the InfoPath form when the workflow task is completed. If we did not do this, then the user could re-submit the form again and again from the Tasks page. There will have to be a feedback mechanism for the InfoPath form to make it aware that the task was completed. We disable the submit button in this example.
    For reference, the snapshots below summarize the procedure of sending the birthday card.
    • Administrator creates a Birthday Card (Figure 1)
    Figure 1
    • Administrator fills out 4 properties of the Word document (Figure 2)
    Figure 2 – Creator fills out 4 fields in the Word properties boxes
    Note that Mary Smith was assigned the task of signing the card (E.g. Assigned To Login Name = MY_NETBIOS_NAMEmarysmith in the property field Figure 2)
    • Exit Word (Figure 3)
    Figure 3 - Exit Word
    • Birthday Card is saved in the SharePoint Library (Figure 4)
    Figure 4
    Workflow is stated automatically on save. ( Figure 5)
    Figure 5 – Our workflow has started.
    We now sign in as Mary Smith, signer of the card. The task is present on her task list. (Figure 6)
    Figure 6 – We are now signed in as Mary Smith
    Mary clicks “Please sign this birthday card” and gets the InfoPath form which she fills out 2 fields. (Figure 7)
    Figure 7 – Mary fills out the form.
    Mary clicks the submit button and the task completes. (Figure 8)
    Figure 8 – Task completed!
    Recipient of the card gets an email with the filled out Birthday Card. (figure 9 & 10)
    Figure 9
    Figure 10
    Word document is fully populated by our Workflow. (Figure 11)
    Figure 11 – Card filled out by the Workflow!
    • Notice that we disable the Submit button in the InfoPath form if Mary tries to fill it out a 2nd time. (Figure 12).
    Figure 12 – Submit button is disabled via feedback from the Workflow on subsequent tries
    So, that’s the flow. It’s very simple from the user’s perspective. However, to get all this working requires a considerable amount of knowledge and work. Let’s get started.
    This tutorial has a huge number steps that need to be performed to set up this workflow. There is very little C# code in the Workflow, and most of the work is done outside of the workflow programming in preparation. Also, this tutorial is quite long since there are so many pieces that need to be discussed to get all of this to work together. Also, there are some issues that would need to be addressed in a production environment. One of them is that we only have one Word document Birthday Card in our SharePoint library. Our C# code references this Word document by its filename and is hard coded. We would need to enhance the C# code to allow any filename to be used for a Birthday Card. One way to do this is to include another property on the Birthday Card Word document named Filename which the initiator of the card would fill out. Another issue is that our InfoPath form takes over the page where a user would normally change the % complete and status of the Workflow. That is why we update the completed status in the Workflow rather than let the user do it manually. Students of SharePoint Minds are encouraged to modify this Workflow to address those issues.
    In any event, this tutorial has a wealth of good information regarding SharePoint workflows that would be helpful.
    To create this work flow, we have to perform the following steps:
    • Create a new library in SharePoint named Happy Birthday Card Library.
    • 2. Create a template for the Birthday Card in the library by defining new columns.
    • 3. Create the Word document Birthday Card.
    • 4. Add the Birthday Card as a content type to the library.
    • 5. Create our InfoPath 2007 task form to accept user input for the From and Message fields.
    • 6. Configure the InfoPath form to receive feedback from the workflow by specifying a secondary data source.
    • 7. Configure the InfoPath form to be presented in a web page with Full Trust security and temporary certificate.
    • 8. Code the Workflow using Visual Studio 2008 in C#.
    • 9. Configure the Workflow in Visual Studio to include the InfoPath form as part of the deployment.
    • 10. Configure the Workflow.xml file so that our InfoPath form is presented to the user in a web page.
    • 11. Configure feature.xml so that our InfoPath form is deployed as a feature.
    NOTE: It should be noted that this author created this library under the Team Site tab of his main portal SharePoint site. This means that the columns that we create (E.g. To, From, Greeting, Assigned to Login Name, Email Address, Completed, and Message) in our Happy Birthday Library are not global site columns, but local to the Team Site.
    The software requirements for this project are significant. The software that you will need is as per the following list:
    • Microsoft ASP.NET 3.5 Framework
    • 12. Microsoft Windows Server 2003 installed on the Virtual Machine (E.g. the VM)
    • 13. Ability of the virtual machine to connect to the internet using the Microsoft Loopback adapter (see the document on this topic by this author on the site).
    • 14. Microsoft SharePoint 2007
    • 15. Microsoft SQL Server 2005 (required by SharePoint)
    • 16. Microsoft Visual Studio 2008
    • 17. Windows SharePoint Services 3.0 Tools: Visual Studio 2005 Extensions, Version 1.2
    • 18. InfoPath Forms 2007
    • 19. Visual Studio Tools for Applications 2007
    • 20. Microsoft Word 2007
    On your SharePoint site (in this case, the authors Team Site), click Site Actions > Create as shown in Figure 13.
    Figure 13
    On the resulting page, click Document Library as shown in Figure 14.
    Figure 14
    Fill out the form for the new library and Click Create. Refer to Figure 15.
    Figure 15
    This will result in a new library as shown in Figure 16.
    Figure 16
    This completes the creation of our library.
    In this step, we are going to create several new columns. These columns will be available in the Happy Birthday Card Word document that we create and will become Word document objects. SharePoint will take care of the linking for us. We will be able to access the contents of the Word objects in the C# code behind. That means that we can read the fields, but it also means that we can write to the fields in the C# code behind in the Workflow. Therefore, the Word document serves as an input form where we can enter values in the fields. It is intended that only 4 of the fields are filled out when the administrator creates a new Birthday Card (E.g. To, Greeting, Assigned To Login Name, Email Address). The remaining fields will be filled out in C# code using data from the InfoPath form.
    In the Happy Birthday Card Library, click Settings > Document Library Settings as shown in Figure 17.
    Figure 17
    Now we want to create some new columns for our Birthday Card. We are going to have to repeat the process for each of our columns. Column names in red are required fields to be filled out by the creator of the card. Our columns are:
    Email Address
    Assigned To Login Name
    The first four columns will be filled out by the person who starts the Birthday Card process from the library. That is, when he/she creates new instance of the Birthday Card by clicking the New > Happy Birthday Card menu selection in the library.
    To: will be the name of the person who will receive the Birthday Card. Example: To: Jane Smith
    Initial Greeting: The second line will be the initial greeting which is the basic text of the card to be displayed. Example: Happy Birthday Jane!
    Email Address: The email address of the recipient of the card.
    Assigned To Login Name: The ID of the person assigned the task of signing the card and providing a message. Example: yourdomainjohnsmith
    The remaining columns will be filled out dynamically by the workflow that we will code. The content of the remaining columns will be obtained from information that is submitted when the signer completes their workflow task by filling out an InfoPath 2007 form during the workflow process.
    So now let’s add come columns. We will only show the process for the first column. The rest of the columns will follow the same procedure.
    Click Create Column as shown in Figure 18.
    Figure 18
    The resulting page is shown in Figure 19. Fill out the form as shown in Figure 19.
    NOTE: All the fields will be single line of text for all our columns. Also, four of the fields will be required fields, so check the radio button to make it a required field. Recall that we denoted the required columns in red above.
    Figure 19
    Repeat this process for our remaining columns. The final result showing all columns created should appear as shown in Figure 20 (except for title which was there already).
    Figure 20 – Our 7 columns added
    Return to the Birthday Card Library in SharePoint. From the New > New Document menu selection, create a new Word document (which will be aware of our columns template that we just created). Refer to Figure 21.
    Figure 21
    An instance of a blank Word document will appear and will show our columns template as shown in Figure 22.
    Figure 22 – Note the text boxes, 4 with red asterisks denoting required fields
    Next, convert the Word document as shown in Figure 23 and Figure 24.
    NOTE: You must convert the document or you will not be able to create the objects that are linked to the 7 site columns that we created.
    From the main menu, click Convert. A dialog will appear as in Figure 24. Click OK.
    Figure 23
    Figure 24
    Now we must save the document to a directory on disk. Do not save the document in the SharePoint library which is the default. Save it to a directory of your choice on disk. To save the document, this author navigated to his My Documents directory as shown in Figure 25.
    Figure 25
    Next, we added a Happy Birthday text at the top and added a picture as shown in Figure 26. Once you have done this, save the document (again).
    Figure 26 – We added a picture and Happy Birthday as text
    Now we need to add some Word Objects to our document in the body just below the picture of the cake. We will perform the following procedure for all of our columns in turn.
    Place the cursor in Word where you would like to create the To object (just below the cake for this one). Then, Click the Insert tab, then Quick Parts > Document Property. Refer to Figure 27.
    Figure 27 – An object corresponding to the menu item To will be placed at the cursor.
    On the resulting dropdown, scroll down to the To listing and click it. This will cause the To object to be inserted at the cursor in the Word document as shown in figure 28.
    Figure 28 – Our To object was inserted at the cursor in Word
    NOTE: These objects in Word will be available in our C# code behind in the workflow. We can either read from them, or write to them in code.
    Perform these steps again in turn, for our remaining objects. When finished, the Word document should appear as in Figure 29.
    Figure 29 – 4 of 7 of our template columns are now objects in the body of the Word document. We never show the other 3 properties on the card.
    Our Word document is now finished. Click save (remember not to save in the SharePoint library, save it to the same directory you have been using), and then exit Word by clicking Exit Word as shown in Figure 30.
    Figure 30 – Exit Word
    Figure 31 – Saving the completed document
    We now need to add our Happy Birthday Word document to our library. To do that, navigate to our Happy Birthday Library, and click Actions > Open in Windows Explorer as shown in Figure 32.
    Figure 32
    When explorer opens, click on the Forms icon, and then you should see the various forms as shown in Figure 33. We need to copy and paste our Happy_Birthday_Card.docx file to this directory. To do that, navigate to the location where you saved the Word document, copy it, and navigate back to this directory and paste it. The result should be as shown in Figure 34.
    Figure 33 – We need to add our Word document here
    Figure 34 – Are new Word document pasted into the directory
    Next, click on Settings > Document Library Settings as shown in Figure 35.
    Figure 35
    We now need to add the content type for our Happy Birthday Card Word document to the library. As shown in Figure 36, click on Add from existing content types.
    Note: if your page does not show the Content Types section, refer to Appendix A to get it to display.
    Figure 36
    Now, using Figure 37, find the content type Birthday Card in the left hand list box, and add it to the right hand list box.
    Figure 37
    Note: The content type of Birthday Card should appear in the left hand list box because we placed our Word document in the Forms directory of the library. Your name may differ depending on what you saved the Happy Birthday Card Word document filename to.
    We should now see a new content type in our library as shown in Figure 38.
    Figure 38
    NOTE: this author recommends that you change the order of the content types shown in Figure 38. Place the Birthday Card content type first, and move Document below it. You can reverse the order by clicking the link just below the red circle in Figure 38 (its cut off in the figure) called Change new button order and default content type.
    Next, we need to specify the template to use for the Birthday Card content type. As shown in Figure 39, click on Advanced Settings.
    Figure 39
    On the resulting page, add the URL of our Happy_Birthday_Card.docx file as shown in Figure 40. Remember we just pasted the document in the forms directory. Click OK.
    Figure 40
    Now, let’s check if our blank Birthday Card loads. As shown in Figure 41, click on New > Birthday Card
    Figure 41
    Our Birthday Card Word document should open up as shown in Figure 42. If it does, all is well and we can move on to the next step. Close the Word document without saving it.
    Figure 42
    This completes step 3.
    QUESTION: Should our Happy Birthday Card been installed as part of the deployment process where a deployment package would be executed on each server in the farm?
    ANSWER: Not necessarily. Remember that content types are stored in the content data base. It will therefore be available to all servers in the farm. So, installing it as we did here only need be done once.
    The purpose of this InfoPath form is to collect the name and birthday greeting from the person assigned the task of signing the card in the workflow. Also, we want it to be presented in a web page rather than in the InfoPath client (which is the default). We will have to specifically configure the InfoPath form to open in a web browser. We also will provide some validation. If either of the 2 fields are blank, we need to prevent the user from submitting the form. Also, we will need to provide the means to disable the Submit button if the workflow has been completed.
    4.1 Open the InfoPath application and create a new blank form project
    We now need to open the InfoPath application and create a new blank template as shown in Figure 43.
    Figure 43
    4.2 – Add a basic layout to the form
    On the resulting screen under Design Tasks, click on Layout as shown in Figure44.
    Figure 44
    Select the Table with Title layout. You should then see a new layout as shown in Figure 45.
    Figure 45
    Change the title to Enter Birthday Card Message as shown in Figure 46.
    Figure 46
    This author changed the color scheme by clicking the navigation items as shown in Figure 47.
    Figure 47
    4.3 – Add 3 rows and split them into 2 columns
    Next, we add 2 rows beneath the title, and then we split those rows into 2 columns as shown in Figure 31. This is done by right clicking on the table, and selecting the appropriate menu items to add rows and split into 2 columns. Refer to Figures 48 & 49.
    Figure 48
    Figure 49
    4.4 Add a text box control to each row
    From the right hand Task Pane as shown in Figure 50, click the drop down arrow and select Controls from the menu. We are now going to add a text box on each of our three rows in the table.
    Figure 50
    Drag a text box onto each row of our table as shown in Figure 51, and add the text in the left hand columns as shown.
    Figure 51
    4.5 – Modify the names of the default DataSource fields assigned to our text boxes
    NOTE: When you create a form template, Microsoft Office InfoPath automatically creates a default data source for you. All InfoPath form templates contain a single, default data source.  You add fields and groups to the main data source by using the Data Source task pane or by dragging a control from the Controls task pane onto a view in the form template. When you drag a control onto a view, InfoPath adds fields and groups to the default data source according to the type of control you are adding. For example, if you drag a text box control onto your form template, InfoPath adds a field to the main data source. In our case, we see three fields added to the default data source since we dragged three text boxes onto our form.
    Figure 52 – Our default data source showing our three fields
    We now want to rename our fields to have them correspond to what our text boxes are intended to contain. Right click on the first text box, and select Text Box Properties as shown in Figure 53.
    Figure 53
    Change the name of the field to From, check the checkbox Cannot be blank and click OK. See Figure 54. Do the same for the 2nd text box, but enter the field name Message and click OK. Do the same for the 3rd text box but enter the name Completed, but do not check the checkbox Cannot be blank. Our form should look like Figure 55.
    Figure 54
    Also, from the Display tab, check the checkbox Read Only for the Completed text box. We do not want the user to be able to type in the Completed text box. We only want him/her to type in the From and Message text boxes.
    Figure 55
    4.6 - Add a button to our form
    We will need a button for the user to click after he/she has filled out the form. We add that now. From the Task Pane on the right, click to get the drop down, and then select Controls from the resulting menu. Drag a button onto our form as shown in Figure 56.
    Figure 56
    4.7 Preview our form to see how it looks.
    Click on the Preview button on the menu bar. The preview should appear as in Figure 57.
    Figure 57 – Preview showing our red asterisks denoting cannot be blank
    4.8 – Change the button title to Submit
    Right click on the button, and click Button Properties from the menu. Enter the name Submit as shown in Figure 58. Click OK.
    Figure 58
    4.9 – Add a rule to the button to disable it if the text boxes are blank
    As in typical .NET programming, we need some validation when the button is clicked on the form. We need to make sure the user entered something in the text boxes. How about if we disable the button until the text boxes contain something? Right click on the button and click on Conditional Formatting as in Figure 59.
    Figure 59
    On the resulting dialog box, Click Add. This causes a 2nd dialog to appear as in Figure 60. Add the condition as shown in the Figure. Also, note that the checkbox Disable this control is checked. This means that if either text box is blank, our Submit button will be disabled.
    Figure 60 – if the condition is true, disable the button
    We now have to add a rule that says when the Completed text box has a value of “1” (denoting the condition true), then we must disable the button in that case as well. So, add a second rule as we did for the first, except this time set the Conditional Format to that shown in Figure 61.
    Figure 61
    We can now test the validation by using the Preview button on the menu bar. In preview mode, add some text to both text boxes. The button should go from the disabled state to the enabled state as shown in Figure 61.
    Figure 61 – test our form in preview mode
    4.10 – Add a rule to send data to the server when the button is clicked.
    We now need to configure the button so that it sends data to the server when the button is clicked. To do that, right click on the button as we have done before, and we get the dialog box as shown in Figure 62.
    Figure 62
    After you click the Rules button as shown in Figure 62, a new dialog will appear. On that dialog click Add to add a new rule. The resulting dialog will appear as in Figure 63.
    Figure 63
    Click on the Set Condition button and a new dialog will appear. Here we are going to configure the button to send data to the server when the From and Message text boxes are populated and the button is clicked. Refer to Figure 64.
    Figure 64 – specify the condition
    Click OK to get back to the previous dialog. On that dialog click on Add Action. In the resulting dialog, click on Submit using a Data Connection. Refer to Figure 65.
    Figure 65 –specify the action for the condition
    Now we have to configure the connection. Click the Add button and a new Wizard will appear as in Figure 66.
    Figure 66 –we are going to submit the data to the server
    Select the defaults as shown in Figure 66 and click Next. The wizard will move to the next screen as shown in Figure 67.
    Figure 67
    As shown in Figure 67, select To the hosting environment, such as an ASP.NET page or hosting application. Then click Next. The wizard will move to the next screen as shown in Figure 68.
    Figure 68 – accept the default name
    Accept the defaults as shown in the Figure and click Finish. When the wizard disappears, we need to add another action to the button. Bring up the dialog as we have done before as shown in figure 69.
    Figure 69 – adding the action to close the form
    Click on Add Action, and in the resulting dialog, click on Close the Form from the dropdown. The results should appear as in Figure 70.
    Figure 70
    Keep clicking OK to close out all the dialog boxes. So, what we have configured is that when the text boxes have text, enable the button. When the button is clicked, submit the data to the server and close the form.
    4.11 – Configure the form to receive data from the workflow on load.
    When the form is submitted, the signer of the card enters text into the From and Message fields that are sent to the server. Our C# code behind in the workflow will read the data submitted and will cause the task to be changed to the completed state when this happens.
    However, the signer of the card could go back to the task list and try to submit the form again. When he/she clicks the Please sign this birthday card link on subsequent tries on the SharePoint Tasks page, the form will load again, but we want to populate the form on these subsequent loads. This is the case where we want to disable the Submit button on the form, and additionally, we would like to populate the form with the values that were originally submitted by the signer. We don’t want to simply put up a blank form again. Remember, the form was already successfully submitted and the task was placed in the completed state.
    So, to populate the form on subsequent loads, and also disable the Submit button, we need to configure a secondary data connection. This data connection will be a receive data connection.
    Adding the Receive Data Connection
    NOTE: The creation of the ItemMetaData.xml file described in the following section was created by this author in the Workflow project in Visual Studio 2008, and the xml file is part of the solution files. It is recommended that you create a Visual Studio Workflow blank project, add an Xml file named ItemMetaData.xml and refer to that file in step 2 below. This tutorial will eventually get to create the workflow in VS2008. Refer to Figure 71. You don’t have to include the file in the project as this author has. You can simply save it to the directory of your choice if you want to.
    Figure 71 – The authors VS2008 solution containing the ItemMetaData.xml file
    We will want to update our task form from the workflow. To send data to the form fields from the workflow, we need to create a receive data connection. For this, we will use a very simple text (XML) file.
    As noted above, create an Xml file in Visual Studio 2008. Name it: ItemMetadata.xml. The name is case-sensitive and any other name will not work (Watch the case of the ‘d’ character, it’s lowercase).
    Inside this file place the following line of text: .
    Save and exit the file. If, in future you want to pass other data back to a task form, just create a similar file and reference the fields in your form by adding ows_ before the field name. You can have multiple fields, separated by a space.
    Back in InfoPath, select Data Connections from the Tools menu.
    Click the Add button and create a new data connection to receive data. A wizard will start as shown in Figure 72.
    Select the radio button Receive Data as shown in Figure 72. Click Next.
    Select XML document as our data source and click Next. See Figure 73.
    In the next wizard screen, browse to ItemMetadata.xml file you just created and select it. Note that it’s the file in our Visual Studio 2008 project. See figure 74 and 75. Click Next.
    IMPORTANT - As shown in Figure 76, select the radio button Include data as a resource file in the form or form template part. Click Next.
    Leave the remaining settings at their default value and click Next until Finished.
    Back in the form, double-click on the From field.
    We’re going to set the default value to that passed into the data connection via the workflow. Click the Fx button next to the default value field as shown in Figure 78.
    Click the Insert field or group button as shown in figure 79.
    From the Data Source drop-down, select ItemMetadata as shown in Figure 80.
    Select the ows_from field and click OK . Refer to Figure 80 again.
    The field should appear as shown in Figure 81. Click OK until all dialogs close.
    Repeat this process for the remaining two fields (E.g. Message and Completed)
    Figure 72
    Figure 73
    Figure 74
    Figure 75
    Figure 76
    Figure 77
    Figure 78
    Figure 79
    Figure 80
    Figure 81
    Q. Where is the ItemMetaData.xml file after you reference it as a secondary data source?
    A. It is embedded as a resource the InfoPath form. We specified this in Figure 76.
    4.12 – Make the form browser compatible
    We want our form to be displayed in a browser, not in the InfoPath client. That means that the form will appear in a web page in SharePoint. To do this, we have to make the form browser compatible.
    On the top menu bar, click Tools > Form Options. A dialog box will appear as shown in Figure 82. On the left hand side, scroll down to Compatibility and click the check box Design a form template that can be opened in a browser or InfoPath. Then click OK.
    Figure 82
    4.13 – Configure the forms Security and Trust settings
    The form will be opened in a web page, and SharePoint will require that the form be trusted. We need to configure the Form so that SharePoint will allow it to be opened.
    On the top menu bar in InfoPath, click Tools > Form Options. A dialog box will appear as shown in Figure 83. On the left hand side, scroll down to Security and Trust and click the radio button Full Trust. Then, check the checkbox Sign this form certificate. You will need to click the button Create Certificate during the process. This certificate will only be a temporary certificate for our development purposes. In practice, a real certificate may be required. When finished, the dialog should look like Figure 83.
    Note: This author found that SharePoint complained that the form was not trusted and would not allow it to be opened. Making the changes to Full Trust with certificate fixed the problem.
    Figure 83
    4.14 – Save the form
    We can now save our form by clicking File > Save from the main menu. We are going to save our form to the same location that we saved our Word document. This author named the file HappyBirthdayForm_one.xsn.
    Note: Do not end the name of the file in a number. Problems can arise since SharePoint can add numbers to the file name under certain conditions.
    4.15 – Publish the form
    We now need to publish our form. Click on File > Publish. The publishing wizard will appear. On the first Wizard dialog, we select the radio button To a Network Location. We then browse to the same location we stored our Word document. This author named this file HappyBirthdayForm_one_Published.xsn. Click out the wizard by taking
    the defaults that are presented.
    Note: The published .xsn file we create will be imported info Visual Studio later in this document. It will then be deployed as a feature where is will show up in Central Administration under Manage Form Templates automatically.
    4.16 – Copy the ID of the form for use in Visual Studio.
    We will need to enter the form ID in the workflow.xml file in Visual Studio since Visual Studio deployment will include our form as a feature. So, let’s copy the ID to the clipboard now. Click File > Properties as shown in Figure 84.
    Figure 84
    As shown in figure 85, copy the ID to the clipboard (and then to NotePad and save it). We will be pasting it into the workflow.xml file in Visual Studio when the time comes.
    Figure 85 – We will need the ID of the form in Visual Studio
    Our form is now finished. We can now close the InfoPath application.
    We can now turn our attention to our workflow project in Visual Studio 2008.
    5.1 Create the project
    Click on File > New > Project as shown in Figure 86.
    Figure 86
    Select the SharePoint 2007 Sequential Workflow as shown in Figure 87.
    Figure 87
    As shown in Figure 88, configure the local site to where the workflow will be used. In this author’s case, it was his Team Site.
    Figure 88 – The author chose his Team Site to use for debugging
    As shown in Figure 89, select Happy Birthday Card Library from the dropdown list titled Library or List.
    Figure 89
    As shown in Figure 90, make sure the checkboxes appear as shown. We need to have the workflow started by either of the two means denoted by the check boxes. Click Finish and our workflow project is created.
    Figure 90
    5.2 – Add activity components from the Toolbox onto the design surface
    We now need to drag some of the workflow components from the toolbox onto the design view. We are going to create a task with a content type, so we need to drag CreateTaskWithContent type object onto our design view. Drag the other objects onto the design view until we have a design view that looks like Figure 91.
    Figure 91
    Note: Each box on the form represents an activity. Blue activities are method activities and green activities are event handler activities.
    5.3 – Add correlation tokens to our activities on the design view
    We now need to set our correlation tokens for all the objects on the form.
    Note on correlation tokens: Each blue and green box (a.k.a activity) on the design view must have a correlation token property set. The important point is that the correlation token for the OnWorkFlowActivated activity must NOT be the same as the other activities on the form (be they blue or green). So, when we set our correlation tokens, we will create a new correlation token name for all the activities OTHER than the OnWorkFlowActivated activity.
    To set a correlation token for each activity, we right click on it, and select Properties from the drop down menu as shown in Figure 92. The procedure is the same for all the activities with the only difference being the name of the token we will enter. We will therefore have two tokens in play:
    • The OnWorkFlowCreated activity has a default correlation token name of workflowToken. We will accept this default.
    • 21. We will create a new correlation token that will be used in every other activity. We will name that correlation token mainToken.
    Figure 92 – Right clicking on an activity to get the corresponding properties box
    In the properties window for each of the activities (other than onWorkflowActivated1), we will type in the name mainToken. Figure 93 and 94 show the results. Note that we need to type (or cut and paste) in the name mainToken four times, once for each activity below onWorkflowActivated1.
    Figure 93 – workflowToken is unique to onWorkflowActivated1
    Figure 94 – All other activities use mainToken as the name
    5.4 – Assign a task ID to createTaskWithContentType as a GUID (Globally Unique Identifier).
    We now add a task ID property to the createTaskWithContentType activity. To get the GUID in Visual Studio, click Tools > Create Guid as shown in Figure 95.
    Note: If your Visual Studio 2008 does not show the Create GUID menu item as shown in Figure 95, refer to Appendix B on how to get it to show up on the menu.
    Figure 95
    Click the radio button as shown in Figure 96 and click Copy. Then paste the GUID into the taskId property as shown in Figure 97.
    Figure 96
    Figure 97
    5.5 – Assign the GUID from Figure 97 to the bottom 3 activities in the design view
    The procedure we denote here will be repeated three times: one for each of the remaining activities (E.g. onTaskCreated1, onTaskchanged1 and completeTask1).
    As shown in Figure 98, click on the ellipsis adjacent to the TaskId property for onTask1created.
    Figure 98
    On the resulting dialog under the tab Bind to an Existing member, under createTaskWithContentType1, click on TaskId. Refer to Figure 99.
    Figure 99
    Click OK, and the TaskId will now be associated with the taskId GUID from createTaskWithContentType1. Repeat this process for the remaining two activities.
    5.6 – Create a rule for the whileActivity1
    So, when the flow gets to the whileActivity1 activity box, what will cause the while loop to exit? At this point, we have to configure the activity to exit by means of a rule. The rule we will use is to exit when the value of a variable (which we will create in a moment) changes from false to true. The variable must be created in the C# code behind and we will name the variable _taskCompleted. Refer to Figure 100 which shows that we added C# code for the variable.
    Figure 100 – we added a new variable called _taskCompleted (defaults to false)
    Now we can set the rule for the while activity. As shown in the property pane for whileActivity1, click on the dropdown and click on Declarative Rule Condition.
    Figure 101
    Then, type in the name whileCondition1in the ConditionName field and then click on the resulting ellipsis as shown in Figure 102.
    Figure 102 – Add the name, then click the elipses
    In the resulting dialog box, type in !_taskCompleted for the condition as shown in Figure 103. Then click OK.
    Figure 103
    5.7 – Try a build: it should be successful
    At this point, try building the solution. You should get a successful build with no errors.
    5.8 – Add method stubs for the five activities in the design view
    Now we need to add the method stubs that we will add code to in the code behind. For each of the activities, double click on each activity in design view. This will cause the stubs to be created for us behind the scenes as shown in Figure 104.
    Figure 104 – an empty stub created for all five activities
    5.9 – Add the code from Appendix C to the stubs.
    The entire code for the workflow is shown in Appendix C. You can cut and paste the code into your solution. At this point, we will discuss the code blocks in turn.
    5.9.1 - onWorkflowActivated1_Invoked
    private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e){
    workflowId = workflowProperties.WorkflowId;
    In the code created for us by Microsoft, we see that the workflowId is assigned a default GUID when the variable id declared. We really want that workflowID to be assigned to the same value as the workflowPropertiesId.
    5.9.2 – createTaskWithContentType1_MethodInvoking
    Figure 105
    This function is called when the task with content type is created. Here we want to retrieve the Happy Birthday Card Word document from the workflowProperties list. It should be noted that there is only one item on the list since we have only 1 document in play at this time (E.g. our Happy Birthday Card document). Recall that the creator of the card typed in the Assigned To Login Name property in the Word document. We need to extract that name here and assign the name to a person who must perform the workflow task. We see that done on line 52. Once we have the assigned to name, we can create the SPWorkflowTaskProperties object required by the workflow. This is done on line 54. By specifying the person assigned to the task, the task to sign the birthday card will show up on that persons Task List in SharePoint.
    5.9.3 – onTaskChanged1_Invoked
    Figure 106
    This function is called when the task changed event fires. For our workflow, this event is fired when the signer of the card submits the InfoPath form we created. This function contains the main code for the workflow.
    Lines 92 and 93 fetch the From and Message strings from the InfoPath form. Note that we have to cast the ExternalDataEventArgs to SPTaskServiceEventArgs to get at these two fields. Next, on line 98, we try to find our Happy Birthday Card Word document as a SPListItem object. Recall that we need to populate two fields on the Happy Birthday Card Word document that were left blank by the creator of the card. The two fields are From and Message (which we just got from the InfoPath form on line 92 and 93). So, we assign those fields to the birthday card on lines 108 and 109.
    Now, since the task is completed by the signer, we also set the Completed field in the Word document as well on line 110. Note that this has nothing to do with the Completed text box in the InfoPath form. The explanation of how the Completed text box works to disable the Submit button in the InfoPath form is given in Appendix D.
    Note that we set the _taskCompleted variable to true on line 111. Recall we set the while loop condition so that the while loop exits when this value becomes true. This is a critical line of code.
    5.9.4 – completeTask1_MethodInvoking
    Figure 107
    This function is called when the while loop exits. All we want to do here is to start the process of emailing our Happy Birthday Card to the intended recipient. So, we simply loop through the items in the library (there is only one in this example) and find our word document. Recall that the missing fields were populated in Figure 106. When we find the document, we pass it to our SendEmail() function.
    5.9.5 – SendEmail
    Figure 108
    This function is used to send the Word Happy Birthday Card to the intended recipient. Note that our Word document is passed to this function as a SPListItem item, not a Word document object. Also, notice on line 197 that we obtain the reply to email address from SharePoint. We configured this in Central Administration > Operations > Outgoing email Settings as shown in Figure 109. Also, notice on line 199 that we specify the mail server to be that configured in SharePoint. In figure 109, that main server is the Outbound SMTP Server, (which is the mail server for hotmail). The issue with using Hotmail as the mail server is that the hotmail mail server is locked down to prevent spam. So, to use it, you have to provide authentication. The authentication credentials are your hotmail username and password. To provide these credentials, we use the NetworkCredentials object (which is also used with many other things in .NET such as web service proxy authentication). Also note that we are specifying to use SSL on line 205.
    Figure 109
    5.9.6 – LogToEventLog
    Figure 110
    To provide logging to the Windows event log, we create our own log named HBEventLog. We navigate to the event log in Windows 2003 by clicking Start > Administrative Tools > Event Viewer. Our log is shown in Figure 111.
    Figure 111
    This concludes the discussion of the C# code.
    So, what is the mechanism by which our InfoPath form is deployed, and what is the mechanism which causes it to be displayed in a SharePoint web page when the signer of the birthday card clicks on the task Please sign this birthday card? (See Figure 6). The answer is in the files workflow.xml and feature.xml. Refer to Figure 112 which shows our Visual Studio project.
    Figure 112
    There are 3 main steps required for the InfoPath form configuration. They are:
    Include the InfoPath form in the Visual Studio Project
    Configure the file workflow.xml
    Configure the file feature.cml
    6.1 – Include the InfoPath form in the Visual Studio Project
    The first thing to notice is that we have included our InfoPath form .xsn file in the project. The name is HappyBirthdayForm_one_Published_deployed.xsn. This form will be deployed as a feature when we click on the Build > Deploy HBWorkflow in Visual Studio. However, we will need to perform steps 2 and 3 for this to happen. The important thing here is that we include the .xsn file in the project. Recall from 4.15 that we published our .xsn file to a directory on disk. Simply include that file in the Visual Studio project (right click HBWorkflow > Add > Existing Item).
    6.2 - Configure the file workflow.xml
    Appendix E has the code for the workflow.xml file as does Figure 113.
    Figure 113
    There are 2 lines of interest here. They are lines 11 and 15.
    Line 11 - We added line 11 with the hexadecimal number as shown. TaskListContentTypeId needs to be set to the value for your task type. If you do not use a custom task list defined in a content type, you can use the value 0x01080100C9C9515DE4E24001905074F980F93160 as shown. In our case, we do not use a custom task list so this number will be used as shown.
    Line 15 – Remember when we copied our InfoPath form ID to the clipboard in Figure 85? That is the ID code we put on this line. The other thing to note is the name of the xml tag we place it in. The tag is and this tag denotes what form should be displayed for the first Task in our sequential work flow (note the character ‘0’). In our case, the first task is defined in the blue box createTaskWithContentType1 in design view. In our case we only have one task, so the Xml tag will be . What if we had a 2nd task object in design view and wanted a different InfoPath form to be displayed for that task? Well, we would define a new Xml tag . Notice that we incremented the number by 1. So, for every task in design view for which we need to show an InfoPath form, we add an XML tag but increment the number by 1. This is actually explained in the notes in the default Workflow.xml, but we have removed those notes for brevity.
    6.3 - Configure the file feature.xml
    The feature.xml file code is in Appendix F and in Figure 114. The key line here is line 13.
    Line 13 specifies the .xsn file that should be deployed as a feature. When we deploy the project using the Visual Studio deployment menu item, the InfoPath form will be installed as a feature for us. Additionally, it will show up in Central Adminstration > Application Management > ManageFormTemplates as shown in Figure 115. We can verify this by going to c:program filescommon filesmicrosoft sharedweb server extensions12TEMPLATEFEATURESHBWorkflow and seeing the .xsn file there after the deployment takes place. See Figure 116.
    Figure 114
    Figure 115
    Figure 116
    We now have all the pieces in place. You can debug the program, or simply run it. Visual Studio will deploy the project each time you debug, so you don’t have to perform a 2 step process of build and deploy. Also, you should be able to exercise the program as denoted in the Figures at the beginning of this tutorial.
    Hopefully, students of this tutorial will find this tutorial helpful in understanding some of the things we went over in class. Also, feedback is encouraged.
    Note: On the resulting page shown in Figure, the Content Types section is shown. If it does not show on your screen, you need to click Advanced Settings on the page and in the resulting page click on the Yes radio button for Allow management of content types as shown in Figure
    Display Create GUID on Visual Studio 2008 Tools menu.
    1. Choose the Tools -> External Tools...
    2. Click the Browse (…) button and find the guidgen.exe in the C:Program FilesMicrosoft SDKsWindowsv6.0ABin folder.
    3. Click the OK button.
    #region using
    using System;
    using System.Diagnostics;
    using System.Net;
    using System.Net.Mail;
    using System.Workflow.Activities;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Workflow;
    using System.Reflection;
    namespace HBWorkFlow
    public sealed partial class Workflow1 : SequentialWorkflowActivity
    #region Declarations
    private const string _formatedErrorMsg = " {0} : {1}" ;
    private const string _errorTitle = " Happy Birthday Workflow : " ;
    private bool _taskCompleted;
    public Guid workflowId = default(Guid);
    public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();
    #region Constructor
    /// Default Constructor

    public Workflow1()
    #region createTaskWithContentType1_MethodInvoking
    /// Event handler called when createTaskWithContentType
    /// event is triggered.

    private void createTaskWithContentType1_MethodInvoking(object sender, EventArgs e)
    SPListItem birthdayCardWordDocument = null;
    SPList list = workflowProperties.List;
    foreach (SPListItem item in list.Items)
    if (item.Name.ToUpper().Equals(" HAPPY BIRTHDAY.DOCX" ))
    { //Address hard coding this later on
    birthdayCardWordDocument = item;
    if (birthdayCardWordDocument == null)
    throw new SPException(" Could not find Word document named 'Happy Birthday.docx' on the list in the library. Unable to proceed." );
    string assignedTo = birthdayCardWordDocument.Properties[" Assigned To Login Name" ] as string;
    createTaskWithContentType1.TaskProperties = new SPWorkflowTaskProperties
    AssignedTo = assignedTo,
    Title = " Please sign this birthday card!" ,
    Description = " InfoPath form presented to a signer of a Birthday Card" ,
    DueDate = DateTime.Now.AddDays(7)
    catch (Exception ex){
    String.Format(_formatedErrorMsg, MethodBase.GetCurrentMethod(), ex.Message),
    #region onWorkflowActivated1_Invoked
    private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e){
    workflowId = workflowProperties.WorkflowId;

    #region onTaskChanged1_Invoked
    /// Event handler called when task is changed. This will occur
    /// when the user submits our InfoPath form.

    private void onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e){
    SPListItem birthdayCardWordDocument = null;
    string from = ((SPTaskServiceEventArgs)e).afterProperties.ExtendedProperties[" From" ] as string;
    string message = ((SPTaskServiceEventArgs)e).afterProperties.ExtendedProperties[" Message" ] as string;
    if (String.IsNullOrEmpty(from) || String.IsNullOrEmpty(message))
    throw new Exception(" From extended property was null and/or Message extended property was null." );
    SPList list = workflowProperties.List;
    foreach (SPListItem item in list.Items)
    if (item.Name.ToUpper().Equals(" HAPPY BIRTHDAY.DOCX" )){
    birthdayCardWordDocument = item;
    if (birthdayCardWordDocument == null)
    throw new Exception(" Birthday Card Word document list item was null." );
    birthdayCardWordDocument.Properties[" From" ] = from;
    birthdayCardWordDocument.Properties[" Message" ] = message;
    birthdayCardWordDocument.Properties[" Completed" ] = " Completed" ;
    _taskCompleted = true;
    catch (Exception ex){
    String.Format(_formatedErrorMsg, MethodBase.GetCurrentMethod(), ex.Message),
    #region LogToEventLog
    /// Our function to log to the Windows Event log

    /// The title to be applied to the
    /// error entry.
    /// The message to appear in the event log.
    /// The message type (E.g. Error, information, etc.
    public static void LogToEventLog(string errorTitle, string message, EventLogEntryType msgType){
    EventLog hblog;
    if (!EventLog.SourceExists(" HBEventLogSource" ))
    EventLog.CreateEventSource(" HBEventLogSource" , " HBEventLog" );
    using (hblog = new EventLog { Source = " HBEventLogSource" })
    hblog.WriteEntry(errorTitle + " : " + message + " : " + msgType);
    catch { }
    #region completeTask1_MethodInvoking
    /// Event handler called when the completeTask event is fired.

    private void completeTask1_MethodInvoking(object sender, EventArgs e){
    SPListItem happyBirthdayWordDocument = null;
    SPList list = workflowProperties.List;
    foreach (SPListItem item in list.Items)
    if (item.Name.ToUpper().Equals(" HAPPY BIRTHDAY.DOCX" )){ //Address hard coding this later on.
    happyBirthdayWordDocument = item;
    catch (Exception ex){
    String.Format(_formatedErrorMsg, MethodBase.GetCurrentMethod(), ex.Message),
    #region SendEmail
    /// Function used to send the Happy Birthday Card Word document
    /// as an attachment.

    /// Our Birthday Card as a SPListItem.
    private void SendEmail(SPListItem happyBirthdayWordDocument)
    #region Programmers Notes
    //This author has SharePoint configured to use Microsoft Hotmail
    //as the outgoing mail server (E.g. as the hotmail outgoing mail server).
    //This is set in Central Administration/Operations.
    //This mail server has security in place such as SSL and is currently requiring authorization.
    //We supply the authorization by means of a NetworkCredentials object. You will have to have an
    //account with the mail service you use so that you can supply your own credentials.
    string toAddress = happyBirthdayWordDocument.Properties[" Email address" ] as string;
    const string subject = " A Birthday Card For You!" ;
    const string messageText = " Please open the attached Birthday Card!" ;
    SPWeb web = workflowProperties.Web;
    string replyTo = web.Site.WebApplication.OutboundMailReplyToAddress;
    MailMessage mailMessage = new MailMessage(replyTo, toAddress, subject, messageText) { IsBodyHtml = false };
    string smtpAddress = web.Site.WebApplication.OutboundMailServiceInstance.Server.Address;
    SPFile attachmentFile = happyBirthdayWordDocument.File;
    Attachment attachment = new Attachment(happyBirthdayWordDocument.File.OpenBinaryStream(), attachmentFile.Name);
    SmtpClient smtp = new SmtpClient(smtpAddress)
    EnableSsl = true,
    UseDefaultCredentials = false,
    Credentials = new NetworkCredential("" , " yourpassword" )
    catch (Exception ex)
    String.Format(_formatedErrorMsg, MethodBase.GetCurrentMethod(), ex.Message),

    APPENDIX D – InfoPath form feedback
    This appendix will attempt to describe the mechanism by which the submit button on the InfoPath 2007 form is disabled after the workflow completes.
    Recall that in Figure 61, we specified that the button should be disabled whenever the text in the Completed text box is set to the number “1”. Nowhere in our code do we see that we as programmers have set this value. In fact, the default value of “0” in the text box when the form is loaded does not come from our C# code either.
    In the topic 4.11 – Configure the form to receive data from the workflow on load, we specified a secondary data source to receive data from the host whenever the InfoPath form loads. We also specified that the ItemMetaData.xml file be used as the secondary data source on receive. If we exercise the sending of the Happy Birthday Card workflow, we see that the InfoPath form contains a value of “0” on first load. However, when the form is submitted, invoking the form a 2nd time shows the value has been set to “1”. Again, we as programmers had nothing to do with these values appearing in the text box.
    This happens because we use the name ows_Completed in the Xml file and reference it in the properties of the Completed text box on the form as shown in Figure A1. This tag appears to be linked to a Boolean value denoting whether or not the task is in the completed state. This goes on behind the scenes and appears to be an undocumented feature from Microsoft.
    Figure A1
    If we tried to substitute a different ows_ value, such as ows_Done (or other name of your choice), then the mechanism will not work, mainly because we cannot set the value to “1” in the C# code behind after the task completes. The key point here is that we would need to set the value after the task completes, but that is too late in the flow to change it.
    As an alternative, if we were to attempt to set a value in the Completed text box before the task completes, say in the createTaskWithContentTpe1_MethodInvoking event handler, then it would work. The value “1” would appear in the InfoPath form. However, the user would be helpless since he/she could not submit the form since the submit button would be disabled on first load! The form is dead from the outset. Not good. We want the “1” to appear on the subsequent loads, but again, that is after the task is completed.
    To set the value of the form on first load (which is useless for us as mentioned above) would require that we include a new property in our C# code called createTaskWithContentType1_TaskProperties since that would give us access to the extendedProperties object. Our code would look like Figures A2 and A3.
    So, where does this leave us to disable the submit button after the task completes? Well, we must use the undocumented feature where the Boolean value of “0” and “1” is provided for us by using ows_Completed as the name in the ItemMetaData.xml file and specified in the binding for the Completed form.
    It would be great if readers of this tutorial could research this further and find documentation on this phenomenon.
    Figure A2
    Figure A3 – This line would set the value in the InfoPath form on 1st load.
    APPENDIX E – workflow.xml

    Name=" HBWorkFlow"
    Description=" My SharePoint Workflow"
    Id=" 68cfd787-087f-4baf-8718-00666bd6afd4"
    CodeBesideClass=" HBWorkFlow.Workflow1"
    CodeBesideAssembly=" HBWorkFlow, Version=, Culture=neutral, PublicKeyToken=c588e451cdda9911"
    TaskListContentTypeId=" 0x01080100C9C9515DE4E24001905074F980F93160" >


    APPENDIX F – Feature.xml

    Title=" HBWorkFlow feature"
    Description=" My SharePoint Workflow Feature"
    Scope=" Site"
    ReceiverAssembly=" Microsoft.Office.Workflow.Feature, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
    ReceiverClass=" Microsoft.Office.Workflow.Feature.WorkflowFeatureReceiver"
    xmlns="" >