Tuesday, April 13, 2010

Creating Custom Workflows in visual studio 2005

Creating Custom Workflows in visual studio 2005


Hi, All

I am going to demonstrate How to create simple holiday approval workflow (SharePoint) in visual studio 2005.

This Visual How To, covers is one where Holiday form is submitted and a manager is required to approve it. Send email notification to Employee Manger about task. If the Holiday form is approved by his/her Manager then send email notification to Employee and Administrator, If rejected then send email notification to Employee only.

The following sections show you how to create a Sequential Workflow project in Visual Studio 2005, create a task form that can be used by a workflow, lay out a workflow, and add code to handle the business logic. It also covers running the project from Visual Studio 2005.

Scenario:



Creating a Visual Studio 2005 Sequential Workflow project


Create one SharePoint list for Holiday submission form:

Create one SharePoint task list with two new columns (Status and Comment):

To create “Status” Column: Go to List setting > Add new column

[Column Name: Status]

[The type of information in this column is: Choice (menu to choose from)]

[Type each choice on a separate line: Pending/Approved/Rejected]



To create “Comment” Column: Go to List setting > Add new column

[Column Name: Comment]

[The type of information in this column is: Multiple lines of text]



To lay out a sequential workflow

1. Open the Visual Studio 2005 project you created earlier.

2. Open the Toolbox. Expand the SharePoint Workflow controls and the Windows Workflow v3.0 controls.

3. Drag an CreateTask activity onto the designer, directly below the onHolidayWorkflowActivated activity.

Note: Do not drop this activity before the onHolidayWorkflowActivated activity; although the designer allows you to do this, the workflow will fail in SharePoint Server.

4. Rename CreateTask activity to createTaskMngrApproval.

5. Next, drag a While activity and drop it below the createTaskMngrApproval activity. Rename this to whileActivityMngr.

6. Drag an OnTaskChanged activity, and drop it inside the While activity that you just created. Rename it to onTaskChangedMngr.

7. Drag a CompleteTask activity and drop it after the While activity. Rename this to completeTaskMngrApproval.

Note: You may see red circles with exclamation points indicating there are problems with your workflow. You handle these in the next section.









Updating the Properties in Your Workflow

You must set some properties before you can move on to enable the workflow engine to process your workflow properly. You will set properties such as the CorrelationToken, which the workflow engine uses to uniquely identify a task, Task Id, Task Properties, and event handlers to provide custom logic. You will start at the top of your workflow and work your way down.

1. To update properties in the activities on your workflow

2. Make sure the properties window is open, and select the onHolidayWorkflowActivated activity.

3. Right-click and select Generate Handlers.

4. The code-behind class opens, and you see an auto generated method stub. Switch back to the Designer.



5. Next, select the createTaskMngrApproval activity.

6. Go to the CorrelationToken property, and type mngrTaskToken.

Note: It is important to point out that the Correlation Token for the workflow should not be used here. Each Task should use its own Correlation Token.



7. Select the TaskId property, and then click the ellipsis (…) button.

8. Select the Bind to a new member tab.

9. Type the following member name: taskId_Mngr.

10. Select the Create Field option button, and then click OK.



11. Select the TaskProperties property, and then click the ellipsis (…) button.

12. Select the Bind to a new member tab.

13. Type the following member name: taskProperties_Mngr.

14. Select the Create Field option button, and then click OK.



15. Right-click the createTaskMngrApproval activity, and then select Generate Handlers.

16. The code-behind class opens, and you should see an auto generated method stub. Switch back to the Designer.



17. Select the whileActivityMngr activity.

18. Select the Condition Property, and in the drop-down list, select Code Condition.

19. Expand the Condition property. Again, you will see a sub-property named Condition. Select this property and type the following text: notFinishedMngr. Press ENTER.

20. Again, the code behind class opens, and you will see an auto generated method stub notFinishedMngr. Switch back to the Designer.



21. Select the onTaskChangedMngr activity.

22. Select the CorrelationToken property, and then in the drop-down list, select mngrTaskToken.



23. Select the TaskId property, and then click the ellipsis (…) button.

24. Select the Bind to an existing member tab.

25. Select the taskId_Mngr property, and then click OK.



26. Select the TaskProperties property, and then click the ellipsis (…) button.

27. Select the Bind to an existing member tab.

28. Select the taskProperties_Mngr property, and then click OK.



29. Right-click the onTaskChangedMngr activity, and then select Generate Handlers. This generates the method stub as you saw previously from the properties window. Switch back to the Designer.

30. Next, set up your BeforeProperties and AfterProperties. To set these up, click the ellipsis (…) button, select to Bind to a New Member. Select create field, and give them the following names: beforeProperties_Mngr, afterProperties_Mngr.

31. Select the completeTaskMngrApproval, and repeat the same steps you just did for the onTaskChangedMngr activity.





Adding Code to the Workflow

Now that you have designed the workflow, you must add code to provide the logic.

Add code to the workflow

Open the workflow1.cs class.

Add properties for the following private fields:

string employeeName;

string strApplicantEmail;

string strAdministratorEmail = "Admin@email.com";

string strResult = "Pending";

string strComment = "Comment:";

bool isFinishedMngr;

StringBuilder strDescription = new StringBuilder();

private void onHolidayWorkflowActivated_Invoked(object sender, ExternalDataEventArgs e)

{

try

{

workflowId = workflowProperties.WorkflowId;

// Set promoted column values.

employeeName = workflowProperties.Item["Created By"].ToString();

}

catch (Exception ex) { }

}

private void createTaskManager_MethodInvoking(object sender, EventArgs e)

{

try

{

char[] CHSharp ={ '#' };

string strLoginName;

string strBody;

string strTitle;

SPSite oSiteCollection = workflowProperties.Site;

SPWeb oWeb = oSiteCollection.OpenWeb();



strLoginName = workflowProperties.Item["Created By"].ToString().Split(CHSharp)[1];//"1;#Domain\\Emp_ID"

SPUser oUserApplicant = oWeb.AllUsers[strLoginName];

strApplicantEmail = oUserApplicant.LoginName;



taskId_Mngr = Guid.NewGuid();

taskProperties_Mngr.TaskType = 1;

strTitle = "Holiday Approval";

taskProperties_Mngr.Title = strTitle;

taskProperties_Mngr.StartDate = DateTime.Today;

taskProperties_Mngr.DueDate = DateTime.Today;





strLoginName = workflowProperties.Item["Manager Name"].ToString().Split(CHSharp)[1];//" 1;#Domain\\Emp_ID "

SPUser oUserManager = oWeb.AllUsers[strLoginName];

taskProperties_Mngr.AssignedTo = oUserManager.LoginName;

//taskProperties_Mngr.AssignedTo = oUserManager["Manager"];



strDescription.Append("<table style='font-size: 12px;'>");

strDescription.Append("<tr><td>Applicant Name:</td><td>" + oUserApplicant.Name + "</td></tr>");

strDescription.Append("<tr><td>Applicant Email:</td><td>" + oUserApplicant.Email + "</td></tr>");

strDescription.Append("<tr><td>From Date:</td><td>" + workflowProperties.Item["From Date"].ToString() + "</td></tr>");

strDescription.Append("<tr><td>Todate Date:</td><td>" + workflowProperties.Item["To Date"].ToString() + "</td></tr>");

strDescription.Append("<tr><td>Reason:</td><td>" + workflowProperties.Item["Reason"].ToString() + "</td></tr>");

strDescription.Append("<tr><td>Phone Number:</td><td>" + workflowProperties.Item["Phone Number"].ToString() + "</td></tr>");

strDescription.Append("<tr><td>Address:</td><td>" + workflowProperties.Item["Address"].ToString() + "</td></tr>");

//strDescription.Append("<tr><td>Item Link:</td><td>" + "<a href='" + workflowProperties.Item.Url.ToString() + "'>Click Here To View details</a>" + "</td></tr>");

strDescription.Append("</table>");



strBody = "<b>Holiday Approval Task is Assigned to you. </b><br>" + strDescription.ToString();



taskProperties_Mngr.Description = strBody;

taskProperties_Mngr.EmailBody = strBody;

taskProperties_Mngr.HasCustomEmailBody = true;

taskProperties_Mngr.SendEmailNotification = true;



}

catch (Exception ex) { }

}

private void notFinishedMngr(object sender, ConditionalEventArgs e)

{

try

{

e.Result = !isFinishedMngr;

}

catch (Exception ex) { }

}

private void onTaskChangedManager_Invoked(object sender, ExternalDataEventArgs e)

{

try

{

Guid oStausFldId = workflowProperties.TaskList.Fields["Status"].Id;

Guid oCommentFldId = workflowProperties.TaskList.Fields["Comment"].Id;

string selStatusValue = afterProperties_Mngr.ExtendedProperties[oStausFldId].ToString();

string selCommentValue = afterProperties_Mngr.ExtendedProperties[oCommentFldId].ToString();

if (!selCommentValue.Equals(""))

{

strComment = "Comment: " + selCommentValue;

}



if (selStatusValue.Equals("Approved"))

{

isFinishedMngr = true;

strResult = "Approved";



}

else if (selStatusValue.Equals("Rejected"))

{

isFinishedMngr = true;

strResult = "Rejected";

}



}

catch (Exception ex) { }

}



private void completeTaskManager_MethodInvoking(object sender, EventArgs e)

{

try

{

string subject;

string body;



subject = "Holiday Request is " + strResult + "!";



body = subject + "<br>" + strDescription.ToString() + "<br>" + strComment;



//Send Email To Applicant

SendMail(strApplicantEmail, subject, body);



//Send Email To Administator

SendMail(strAdministratorEmail, subject, body);



}

catch (Exception ex) { }

}



private void SendMail(string To,string Subject,string Body)

{

try

{

SPSite oSiteCollection = workflowProperties.Site;

SPWeb oWeb = oSiteCollection.OpenWeb();

SPUtility.SendEmail(oWeb, true, true, To, Subject, Body);

}

catch (Exception ex) { }

}



Folder Structure:



Updating the Workflow.xml File

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<Workflow

Name="HR Holiday Approval"

Description="Workflows that send a Holiday request form for approval."

Id="{5ESDA45BE2-AFBB-45a2-891E-8227ABDAA42B}"

CodeBesideClass="HRHolidayWorkFlow.Workflow1"

CodeBesideAssembly="HRHolidayWorkFlow, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bd27a3dsf458edb55f226"

StatusUrl="_layouts/WrkStat.aspx">

<Categories/>

<!-- Tags to specify InfoPath forms for the workflow; delete tags for forms that you do not have -->

<MetaData>

<AssociateOnActivation>false</AssociateOnActivation>

</MetaData>

</Workflow>

</Elements>





Updating the Feature.xml File

<?xml version="1.0" encoding="utf-8"?>

<Feature Id="{822345A0-036E-438f-8853245-3EB336DDBB69}"

Title="HR Holiday Approval Workflow"

Description="Workflows that send a Holiday request form for approval."

Version="12.0.0.0"

Scope="Site"

xmlns="http://schemas.microsoft.com/sharepoint/">

<ElementManifests>

<ElementManifest Location="workflow.xml" />

</ElementManifests>

<Properties>

<Property Key="GloballyAvailable" Value="true" />

<!-- Value for RegisterForms key indicates the path to the forms relative to feature file location -->

<!-- if you don't have forms, use *.xsn -->

<Property Key="RegisterForms" Value="*.xsn" />

</Properties>

</Feature>



Create Install.bat File



echo Copying the feature...



rd /s /q "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\HRHolidayWorkFlow"

mkdir "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\HRHolidayWorkFlow"



copy /Y DeploymentFiles\FeatureFiles\feature.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\HRHolidayWorkFlow\"

copy /Y DeploymentFiles\FeatureFiles\workflow.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\HRHolidayWorkFlow\"



echo Adding assemblies to the GAC...



"%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -uf HRHolidayWorkFlow

"%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if bin\Debug\HRHolidayWorkFlow.dll



echo Activating the feature...



pushd %programfiles%\common files\microsoft shared\web server extensions\12\bin



stsadm -o installfeature -filename HRHolidayWorkFlow\feature.xml -force

stsadm -o activatefeature -filename HRHolidayWorkFlow\feature.xml -url http://Server1234:1000/



echo Doing an iisreset...

popd

iisreset

pause







Create Uninstall.bat File



pushd %programfiles%\common files\microsoft shared\web server extensions\12\bin



stsadm -o deactivatefeature -filename HRHolidayWorkFlow\feature.xml -url http://Server1234:1000/

stsadm -o uninstallfeature -filename HRHolidayWorkFlow\feature.xml



echo Doing an iisreset...

popd

iisreset

pause





Enjoy….





My New Documentation on:

1. How to deploy WorkFlow using WSP File.



2. How to attach workflow to a list.





No comments:

Post a Comment