I want to clarify the well known WSS SP1 declarative workflow issue that’s found in abundance on the web. We ran into this recently when attempting to use the Start Another Workflow activity that comes with the Useful SharePoint Designer Custom Workflow activities codeplex solution. Actually, if you read through the comments on codeplex, others are having the same problem with nothing really identified as the fix. This post will outline our solution, along with some guidance on the recommended Microsoft route.
This issue is outlined in detail here: http://support.microsoft.com/kb/947284.
Directly from MS: After you install Windows SharePoint Services 3.0 SP1, declarative workflows do not start automatically if the following conditions are true:
- The Windows SharePoint Services Web application runs under a user’s domain account.
- The user logs in by using this domain account.
- The site displays the user name as System Account.
So typically, when we install SharePoint 2007, we have a domain admin account that we do the installation under, or even a local administrator, and we specify a service account during installation that’s responsible for running our services and app pools. You’ll notice that when you log into SharePoint using this service account, regardless of the name of that service account, it will display System Account. This is important to understand.
What Microsoft is asking us to do is change the application pool, so it runs under someone other than what you’ve specified for the service account. So, if for example our service account upon installation was domain\wss_service, our app pool will run under domain\wss_service. You’ll need to change that to domain\new_account.
Ok so none of that was really new information, but I do want to shed some light on the issues that users are experiencing with the Start Another Workflow activity that was the original motivation behind this post. Basically, if you look through the codebase, Start Another Workflow uses elevation to do what it needs to do, to trigger the requested workflow. Elevation always runs under the credentials of the account specified to run the application pool. Read this post and it’s comment entirely to understand this process: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx.
Because we’re trying to trigger another workflow (that’s the whole point of this activity) and we’re doing it while elevated, thus running as the app pool account, IF this account also happens to be the System Account, you will receive the declarative workflow error. So, again, you either change that app pool account, or you can do something like this:
// even when taking the elevation out of this code, the workflow would still // trigger as System Account. In theory, users may not have Start Workflow permissions // on a given list, so it makes sense to impersonate and leverage a workflow_svc account SPUser user = web.SiteUsers[@"domain\\new_account"]; // we could use: __Context.Web.CurrentUser.UserToken // but what if user does not have access, so we use user instead SPSite site2 = new SPSite(site.ID, user.UserToken); SPWeb web2 = site2.OpenWeb(); // using the debugging information below, we are able to see the following output: // user running under: Joe User // site user: Sytem Account // context user: Joe User // so the web objected instantiated above is using the System Account context string userString = "user running under:" + __Context.Web.CurrentUser.Name; string siteUser = "site user:" + web.CurrentUser.Name; string contextUser = "context user:" + web2.CurrentUser.Name; Common.AddCommentWorkflowHistory(userString, executionContext, this.WorkflowInstanceId); Common.AddCommentWorkflowHistory(siteUser, executionContext, this.WorkflowInstanceId); Common.AddCommentWorkflowHistory(contextUser, executionContext, this.WorkflowInstanceId); // so when we create our SPList object below, we have to use web2, not web // so that we can make sure our workflow runs under the user context not System Account // why don't we want to run under System Account? because SP1 prevents declarative workflows. SPList list = web2.Lists[new Guid(ListId)]; SPListItem listItem = list.GetItemById(ListItem); SPWorkflowAssociation myWorkflowAssoc = null; //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); if (myWorkflowAssoc != null) { // using site2 to start the workflow is not enough, the listItem passed into the StartWorkflow // method has to have been instantiated using the web2 object site2.WorkflowManager.StartWorkflow(listItem, myWorkflowAssoc, myWorkflowAssoc.AssociationData, true); } site2.Close(); web2.Close(); |
The above code is a direct replacement of what’s currently in source on codeplex for the Start Another Workflow activity. This is just presented as an option to those not wanting to change their app pool configuration for whatever reason.