Wednesday, November 18, 2009

Custom Workflow in Project Server 2007 - Part 4

Part 1
Part 2
Part 3


Writing Codes for Activities

Add the following using directives to the top of the class file, If already not there:

using Microsoft.SharePoint.Workflow;
using System.Collections.Specialized;
using System.Text;
using Microsoft.SharePoint;


Add the following class member fields :

public string m_ProjectName;
public bool m_LoginSuccessfull;
public int m_PublishRequestUserId;


OnWorkflowActivated1_Invoked - This is the first method to be called in the workflow execution. Add the following code to initialize some variables using the workflowProperties field (extracting properties from the list item that initiated the workflow).

private void OnWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
{
workflowId = workflowProperties.WorkflowId;
m_ProjectGuid = new Guid((string)workflowProperties.Item
[EPMWFConstants.CON_ProjectGuidColumn]);
m_ProjectName = (string)workflowProperties.Item
[EPMWFConstants.CON_ProjectTitleColumn];
string userToken = (string)workflowProperties.Item
[EPMWFConstants.CON_PublishRequestorColumn];
m_PublishRequestUserId = Convert.ToInt32(userToken.Substring(0,userToken.IndexOf(";")));
}


SendRequestsForApproval_Invoking - Set up the email fields for the request to approvers.

private void SendRequestsForApproval_Invoking(object sender, EventArgs e)
{
m_MailToHeader = new StringDictionary();
StringBuilder returnString = new StringBuilder();
SPGroup approverGroup = workflowProperties.Web.SiteGroups[EPMWFConstants.CON_ApproversGroupName];
foreach (SPUser currentApprover in approverGroup.Users)
{
if (!string.IsNullOrEmpty(currentApprover.Email))
{
returnString.AppendFormat("{0};", currentApprover.Email);
}
}
m_MailToHeader.Add("To", returnString.ToString());
m_MailToHeader.Add("Subject", string.Format("Project publishing approval request : \"{0}\"", m_ProjectName));
StringBuilder mailBody = new StringBuilder();

mailBody.AppendFormat("{0} has requested approval to publish the Project" +
"\"{1}\".
", workflowProperties.Web.Users.GetByID(m_PublishRequestUserId).Name, m_ProjectName);
m_MailToBody = mailBody.ToString();
}


SendPendingApproval_Invoking - Send pending notices to publishers

private void SendPendingApproval_Invoking(object sender, EventArgs e)
{
m_MailToHeader = new StringDictionary();
m_MailToHeader.Add("To", workflowProperties.Web.Users.GetByID(m_PublishRequestUserId).Email);
m_MailToHeader.Add("Subject", string.Format("Project \"{0}\" submitted for approval", m_ProjectName));
m_MailToBody = "The project has been submitted for " +
"approval. You will be notified when the item has been approved/rejected.";
}


WhileWaitingForApproval_Condition - Set Result to true if the status on the list item is set to Waiting for Approval,which causes the loop to continue.

private void WhileWaitingForApproval_Condition(object sender, ConditionalEventArgs e)
{
e.Result = (string)workflowProperties.Item[EPMWFConstants.CON_ApprovalStatusColumn] == EPMWFConstants.CON_StatusWaitingText;
}


IfApproved_Condition - checks whether the item is approved Else assumes that the item has been rejected.

private void IfApproved_Condition(object sender, ConditionalEventArgs e)
{
e.Result = (string)workflowProperties.Item[EPMWFConstants.CON_ApprovalStatusColumn] == EPMWFConstants.CON_StatusApprovedText;
}


PsiQueuePublish_Invoking - code for the actual web service call
to the Queue System PSI.

private void PsiQueuePublish_Invoking(object sender, InvokeWebServiceEventArgs e)
{
//Create a new Job Guid for this operation
m_PublishJobGuid = Guid.NewGuid();
//Get the web service proxy from the activity
EPMWF.psiProjects.Project webService = (EPMWF.psiProjects.Project)e.WebServiceProxy;
//use the default credentials
webService.UseDefaultCredentials = true;
//Set the URL to the web service
webService.Url = workflowProperties.WebUrl + "/_vti_bin/PSI/Project.asmx";
//Set an empty string for the publish wss url
m_PublishWssUrl = string.Empty;
}


SendApproval_Invoking - Send an Approved notification to requester.

private void SendApproval_Invoking(object sender, EventArgs e)
{
string subject = "Publishing of Project \"{0}\" has been APPROVED";
string body = "Publishing of the project \"{0}\" has been approved.";
m_MailToHeader = new StringDictionary();
m_MailToHeader.Add("To", workflowProperties.Web.Users.GetByID(m_PublishRequestUserId).Email);
m_MailToHeader.Add("Subject", string.Format(subject, m_ProjectName));
m_MailToBody = string.Format(body, m_ProjectName);
}


SendRejected_Invoking - Send an rejected notification to requester.

private void SendRejected_Invoking(object sender, EventArgs e)
{
string subject = "Publishing of Project \"{0}\" has been REJECTED";
string body = "Publishing of the project \"{0}\" has been rejected.";
m_MailToHeader = new StringDictionary();
m_MailToHeader.Add("To", workflowProperties.Web.Users.GetByID(m_PublishRequestUserId).Email);
m_MailToHeader.Add("Subject", string.Format(subject, m_ProjectName));
m_MailToBody = string.Format(body, m_ProjectName);
}


Deploying the Solution

  • Sign assembly with a strong name key & install in the Global Assembly Cache

  • Workflow registration with WSS - create and register a feature that exposes the custom workflow.

    • Create following dir ,sub dir & files in your Project/Solution dir
      \TEMPLATE\FEATURES\EPMWF

    • Add two xml files , feature.xml & workflow.xml in this sub dir

    • open the feature.XML file and add the following:

      <?xml version="1.0" encoding="utf-8" ?>
      <Feature xmlns="http://schemas.microsoft.com/sharepoint/"
      Id="{guid}" Title="EPM Workflow Sample" Scope="Site" Hidden="False" Version="1.0.0.0">
      <ElementManifests><ElementManifest Location="workflow.xml" /></ElementManifests>
      <Properties><Property Key="GloballyAvailable" Value="true" /></Properties>
      </Feature>

      Create a new GUID and replace the {guid}tag.

    • open the workflow.xml file and add the following:

      <?xml version="1.0" encoding="utf-8" ?>
      <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <Workflow Id="{guid}" Name="Publishing Approval" Description="EPM Publishing Approval" CodeBesideClass="EPMWF.PublishingWorkflow" CodeBesideAssembly="EPMWF, Version=1.0.0.0, Culture=neutral, PublicKeyToken={token} " >
      <Categories />
      <MetaData><StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl></MetaData>
      </Workflow>
      </Elements>

      Replace the {token} tag with the public key token of your assembly.
      Create a new GUID and replace the {guid}tag.

    • Install and activate this feature on your PWA site
      %STSADM% -o InstallFeature -filename EPMWF\feature.xml –force
      %STSADM% -o activatefeature -name EPMWF -url http://server/PWA

    • Attach the workflow to the custom list - browse to the Workflow Settings page. Select Publishing Approval Workflow ,set Name field,task and history lists. Finally, select Start This Workflow When a New Item Is Created under Start Options.


  • Registering the server-side event handler with Project Server 2007-

    • Browse to the ‘Server-Side Event Handler Configuration’ page link.
    • select the Publishing event for Project group, and click the link.
    • Add a new handler by clicking the New Event Handler link.
    • Enter a name such as ‘EPM Publishing Workflow’ and a description.
    • Then enter the assembly name - name, Version=1.0.0.0, Culture=neutral, PublicKeyToken={token}
    • Enter the class name - .
    • enter 1 as the order of the handler.
    • Click the Save button to register the event handler

    For More details on Project server Event Handler check this article .


For testing Create a new project using Project Professional or Create a Proposal using PWA site and publish it.

No comments: