End Selected Workflow - Modification of "Start Another Workflow"

Jul 25, 2008 at 1:41 PM
Edited Jul 25, 2008 at 1:43 PM
First of all I want to say THANK YOU for this great group of custom actions for SPD :) Very useful and very well packaged.

We just recently started doing some stuff with Workflow and I came into a problem.  We have a contact form that anonymous users can submit if they want more information on a product or service, the form was created as a "Webpart", the webpart stores all of the users response information in a database, then creates a new list item in a "Response" list and based upon what products/services the user was interested in it will send an email to the agent who will most likely be able to help this person, along with a link to the list item they must update.

Our "response" list is designed to keep track of how the response is going, and after the agent has made contact with the person they can fill in the conclusion of the lead and mark it as completed.  We have a field called "ScheduledFollowUpDate" so that if the agent gets the information, but does not have time to contact the person they can schedule a day to continue the process.  The workflow we wrote basically says IF the current contact isn't marked as completed, THEN pause until ScheduledFollowUpDate.  However if it is marked as "Completed" then it checks certain fields to make sure everything is filled out, then it fires a custom action that will write the response information to the database and delete the current list item (We are still working on this action, we are not in production yet).

Ok now for the workflow part :)  The problem we were having is if an agent updates the list with more information and marks it as completed or changes the ScheduledFollowUpDate or ContactDate or whatever.....the workflow doesn't restart itself! Its still paused and waiting to send the reminder email, even though the agent might have already completed the response!  So what I did below is I modified the "Start Another Workflow" and created a "End Selected Workflow" that essentially works just like the Start Another Workflow, except it will end a workflow on the current list item that you type in.  It wasn't a lot of modification so once again I want to thank all the people working on this project, keep it up :)  By creating this, what I did is the "Logic" workflow now starts on the creation of the item and thats it. I created another workflow called "RestartResponse" that fires off on update, all it does is Stops the current "Logic" workflow, then starts another instance of it and then shuts itself down. That way EVERY TIME the agent updates that list item, the logic refreshes itself and either sets up the new date for the reminder email, or completes the response and fires our last custom action :)

Code for "End Selected Workflow" (Note I have bolded the changes I made)

using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.ComponentModel;
using Microsoft.SharePoint.WorkflowActions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

namespace EBSCO.Workflows
{
    /// <summary>
    /// ends a selected workflow associated with a list
    /// This code was taken from http://www.codeplex.com/SPDActivities and then modified.
    /// </summary>
    public class EndSelectedWorkflow : Activity
    {
        public static DependencyProperty __ContextProperty = System.Workflow.ComponentModel.DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(EndSelectedWorkflow));


        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public WorkflowContext __Context
        {
            get
            {
                return ((WorkflowContext)(base.GetValue(EndSelectedWorkflow.__ContextProperty)));
            }
            set
            {
                base.SetValue(EndSelectedWorkflow.__ContextProperty, value);
            }
        }


        public static DependencyProperty ListIdProperty = System.Workflow.ComponentModel.DependencyProperty.Register("ListId", typeof(string), typeof(EndSelectedWorkflow));

        [Description("ID of the list we are working with")]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string ListId
        {
            get
            {
                return ((string)(base.GetValue(EndSelectedWorkflow.ListIdProperty)));
            }
            set
            {
                base.SetValue(EndSelectedWorkflow.ListIdProperty, value);
            }
        }

        public static DependencyProperty ListItemProperty = System.Workflow.ComponentModel.DependencyProperty.Register("ListItem", typeof(int), typeof(EndSelectedWorkflow));

        [Description("ID of the list item we are working with")]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int ListItem
        {
            get
            {
                return ((int)(base.GetValue(EndSelectedWorkflow.ListItemProperty)));
            }
            set
            {
                base.SetValue(EndSelectedWorkflow.ListItemProperty, value);
            }
        }

        public static DependencyProperty WorkflowIdentifierProperty = System.Workflow.ComponentModel.DependencyProperty.Register("WorkflowIdentifier", typeof(string), typeof(EndSelectedWorkflow));

        [Description("Workflow name or template base id")]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string WorkflowIdentifier
        {
            get
            {
                return ((string)(base.GetValue(EndSelectedWorkflow.WorkflowIdentifierProperty)));
            }
            set
            {
                base.SetValue(EndSelectedWorkflow.WorkflowIdentifierProperty, value);
            }
        }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            try
            {   //need to run under SHAREPOINT\system account because workflow owner might not have end workflow permissions on the target list
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(__Context.Site.ID))
                    {
                        using (SPWeb web = site.AllWebs[__Context.Web.ID])
                        {
                            SPList list = web.Lists[new Guid(ListId)];

                            SPListItem listItem = list.Items.GetItemById(ListItem);

                            SPWorkflowAssociation myWorkflowAssoc = null;

                            //create a collection of ALL active workflows for the current item
                            SPWorkflowCollection myWorkFlowCollection = site.WorkflowManager.GetItemActiveWorkflows(listItem);                           

                            //resolve any lookup parameters
                            string wkId = Common.ProcessStringField(executionContext, this.WorkflowIdentifier);

                            //find workflow association by name
                            myWorkflowAssoc = list.WorkflowAssociations.GetAssociationByName(wkId, System.Threading.Thread.CurrentThread.CurrentCulture);
                            //cycle through all the active workflows
                            foreach (SPWorkflow myWorkflow in myWorkFlowCollection)
                            {
                                if (oWorkflow.AssociationId == myWorkflowAssoc.Id)  //if one of the active workflows is the same as the selected
                                {
                                    site.WorkflowManager.RemoveWorkflowFromListItem(myWorkflow); //then end it!
                                }
                            }


                        }

                    }

                });
            }
            catch (Exception e)
            {
                Common.LogExceptionToWorkflowHistory(e, executionContext, this.WorkflowInstanceId);

                throw;

            }

            return ActivityExecutionStatus.Closed;
        }
    }
}