Starting Workflows for Anonymous Users in SharePoint 2010
- Posted in:
- SharePoint 2010
During one of the service packs to SharePoint 2007 the ability to run anonymous workflows was turned off and to the best of my knowledge a good solution to the issue was never found (even for SharePoint 2010). I tried solutions such as http://wssguestaccount.codeplex.com/ and other like this but had run into constant issues with the entire user session being run as an impersonated user. Clients kept asking me for a solution and after searching around with no luck I decided it was time to write a little code.
Enter the SharePoint 2010 "Site Level" event receiver. While workflows require a logged in user, the SPItemEventReceiver is not quite as picky and they run anytime an item is added or updated anywhere on our site (SPWeb). So how does this help you might ask? Well the basic idea is if a new item is created or an item is modified, we can find the workflows associated with that item a launch them. Here is the code I use to do just that:
private void _checkWorkflows(SPListItem li, EventType et) { SPSecurity.RunWithElevatedPrivileges(delegate() { SPUserToken token = null; using (SPSite site = new SPSite(li.ParentList.ParentWeb.Site.ID)) { using (SPWeb web = site.RootWeb) { try { string usr = web.AllProperties.ContainsKey(AnonWorkflowReceiverSettings.AnonWorkflowReceiverSettingsRunAs) ? web.AllProperties[AnonWorkflowReceiverSettings.AnonWorkflowReceiverSettingsRunAs] as string : "SHAREPOINT\\System"; token = web.GetUserToken(usr); } catch { token = site.SystemAccount.UserToken; } } } using (SPSite site = new SPSite(li.ParentList.ParentWeb.Site.ID, token)) { using (SPWeb web = site.OpenWeb(li.ParentList.ParentWeb.ID)) { SPList list = web.Lists[li.ParentList.ID]; SPListItem listItem = list.Items.GetItemById(li.ID); foreach (SPWorkflowAssociation wf in list.WorkflowAssociations) { if ((et == EventType.Added && wf.AutoStartCreate) || (et == EventType.Updated && wf.AutoStartChange)) { foreach (SPWorkflow runningWF in listItem.Workflows) { if (runningWF.Author == -1) // Kill all running WF that are anonymous since they will fail anyway { SPWorkflowManager.CancelWorkflow(runningWF); } } site.WorkflowManager.StartWorkflow(listItem, wf, string.Empty, SPWorkflowRunOptions.Synchronous); // Works Async too } } } } }); } private enum EventType { Added, Updated }
You might notice that we have to run the workflow as a specific user and to do that I store the user name in the root web's property bag. I do default to the system account if no value is in the property bag but I suggest no running your workflows this way. The rest is just setting up your event receiver and adding a way for you to assign the user to run the workflow as. To do that I suggest you check out Creating SharePoint 2010 Event Receivers in Visual Studio 2010 and I added a page to the _layouts directory and add a custom link to it in Site Settings using a Custom Action.
So far the solution is working great for anonymous forms and other items that we allow users to submit on public web sites. As always though, please test before using this code in production or drop me a line if you need any consulting help.
I hope this helps someone.
Cheers,
James