After Service Pack 1 and the inherent security improvements that had been implemented you may find yourself having issues with SharePoint Designer workflows kicking off automatically. One way that we have found around that issue is setting workflows in a list / library that you know will have that issue to manual start only and register a custom event handler on that list for ItemAdded or ItemUpdated to manually kick off the workflow through code.
That in itself is a nice workaround, but what if you wanted to kick off a workflow using another users context, but you don’t want to store credentials or any other pesky security information in your code?
In this specific scenario we created a workflow service account that we wanted to use to kick the workflow off on a form library where items were being submitted through InfoPath Forms Services (and because these workflows were creating, updating, and looking inside other lists that we needed to set security we only needed to do it for this one service account). Here is a bunch of code:
//Set variables from web.configstring _workflowUser = ConfigurationSettings.AppSettings["WorkflowUser"]; //Example:DOMAIN\Administratorstring _workflowName = ConfigurationSettings.AppSettings["WorkflowName"]; //Example:Master Workflowstring _formsLibrary = ConfigurationSettings.AppSettings["FormsLibrary"]; //Example:Request LibrarySPSecurity.RunWithElevatedPrivileges(delegate(){ //Setting variables to use under workflow service account string userName = properties.UserLoginName; int itemID = properties.ListItemId; SPWeb parentWeb = properties.OpenWeb(); SPList parentList = parentWeb.Lists[_formsLibrary]; string targetUrl = parentWeb.Url; SPUser workflowUser = parentWeb.AllUsers[_workflowUser]; //Open site as workflow service account SPSite site = new SPSite(targetUrl, workflowUser.UserToken); site.AllowUnsafeUpdates = true; //Open web as workflow service account SPWeb web = site.OpenWeb(); web.AllowUnsafeUpdates = true; //Get Item object as workflow service account SPList formsLibrary = web.Lists[_formsLibrary]; SPListItem item = formsLibrary.GetItemById(itemID); //Getting workflow information SPWorkflowAssociation workflowTemplate = formsLibrary.WorkflowAssociations.GetAssociationByName(_workflowName, System.Globalization.CultureInfo.CurrentCulture); //Getting workflow Manager to start workflow SPWorkflowManager mgr = site.WorkflowManager; //Starting workflow as service account mgr.StartWorkflow(item, workflowTemplate, workflowTemplate.AssociationData); web.Dispose(); site.Dispose(); parentWeb.Dispose();});
First off I’m getting my variables from my web.config appSettings, you could just as easily set these in a property bag on an SPSite or SPWeb object. After that, I start running the next few lines in the context of the application pool so that I know I have access for everything I need to populate other variables I will need down the road. The fun part comes when I open the SPSite site object using the workflowUser.UserToken object. After that all items that I use the parent site object to obtain is opened up as that workflowUser