Workflow: tasks which can only be actioned by task owner

When coming to Visual Studio workflows, something which surprises many SharePoint developers is that tasks assigned in the workflow can actually be actioned by any SharePoint user with basic permissions. In the worst scenario, ‘basic permissions’ means any user with contribute permissions to the SharePoint web which contains the workflow tasks list, and clearly this could be a whole lot of users who have nothing to do with your workflows. In the best case, you might have tied down permissions so that only users involved in workflows can use the list. Even so, this still means that any actor in the workflow can respond to any task, not just tasks which have actually been assigned to them. To my mind, this is bad – all it takes is a confused user to accidentally respond to someone else’s task and your workflow is in a whole world of chaos.

So what can we do about this?

Well, there doesn’t seem to be much written about this, but fortunately the best solution (AFAIK) is also the simplest one. Before we dive in, I notice other people needing to solve this problem have taken the approach that since a workflow task is just a list item, we can execute some code to set permissions on the list item using the API. A logical tactic, but happily there is special provision for doing this in the workflow framework – we still need to write a little code, but it’s much simpler than that approach. The key is the ‘SpecialPermissions’ property of the CreateTask activity:

Pitfall – confusingly, clicking the ellipses button (…) for the property presents a generic VS collection editor (shown below), which as far as I can tell just flat cannot be used with this property – all the controls are disabled!

I’m assuming this is a bug in the Visual Studio 2005 Extensions for Workflow Foundation, so we’ll ignore that! However, clicking the tiny blue ‘bind property’ button presents the more familiar ‘bind the property to an instance variable’ dialog – assuming you haven’t already created a variable to store the permissions for this CreateTask, we should select ‘Bind to a new member’, and create either a field or property to store the permissions:

This creates a collection object, specifically a HybridDictionary, to which we can add items for each permission we need for this task. And we only need a handful of code lines to do it! Since we’re likely to use it for many (i.e. all) tasks in our workflow, let’s have a separate method we can call each time:

private void setTaskPermissions(HybridDictionary boundDictionary, string sTaskOwner)

{

     boundDictionary.Clear();

     boundDictionary.Add(sTaskOwner, SPRoleType.Contributor);

     boundDictionary.Add(“NT AUTHORITY\\authenticated users”, SPRoleType.Reader);

}

So, we pass in the collection specific to each task, and also the string username for the task owner. We then add an entry for the task owner to the dictionary with the ‘contributor’ permission, and one for all other users with just read permissions. Note we also clear out the dictionary before adding in case this task has already been issued (i.e. something got rejected in the workflow and we came back to this task a second time) – this avoids any errors due to the key already existing in the dictionary.

The calling code then, looks like this:

setTaskPermissions(approveExpenseClaim_SpecialPermissions, taskProps.AssignedTo);

This would be added to the code for each CreateTask activity in your workflow. The first parameter is the variable we bound earlier to the SpecialPermissions property (of the particular task we are dealing with), and taskProps is the SPWorkflowTaskProperties object which holds data for the task.

And that’s it – much less code than you’d need to modify permissions for the list item with general API usage. The effect of this is that the task owner is the only standard user (administrators with full control excepted) who can respond to the task, but all others can read it. Needless to say, you could customize the code to your specific permission requirements if they are different to mine.

The user experience

One final thing worth pointing out is that the user experience might not be quite as slick as you’d like. Since we’ve restricted permissions on the item, any user who clicks on the task but doesn’t have permissions will see the standard access denied message:

Personally I think an improvement would be to show a more friendly message, but this would require substantially more effort and complexity. My view is that for a few lines of code, this approach is a great trade off between effort required and benefit of protecting the integrity of the workflow – I’m definitely not a fan of sleepless nights wondering just what would happen in the workflow if users unintentionally responded to tasks which didn’t belong to them, so it works for me. As always, if you’ve implemented a different way of dealing with this problem or have other comments, it would be great to hear.

Resources from my workflow deep-dive presentation

Had a lot of fun presenting VS workflows at the UK SharePoint user group last night. We seemed to have weather issues (again) which might have put some people off travelling, but we still had a great crowd of around 100-120 people. As promised, here are my resources (my ‘workflow bonanza pack’ in fact ;-)). In the zip behind the link below, you will find:

  • Slide deck (presentation title: “Workflow: A deep dive into developing workflows for SharePoint using Visual Studio and Infopath”)
  • Sample code for the state machine expenses workflow I built
  • My workflow information pack document

Much of the goodness is in the document – the contents are:

  • Links to my favourite workflow resources (blogs, books etc.)
  • How to: work with SharePoint tasks and e-mails in workflows
  • How to: Pass data into an InfoPath task edit form
  • How to: retrieve what the user entered into an InfoPath task edit form
  • How to: debug a workflow
  • How to: use serialization to retrieve data from an InfoPath form
  • Advanced workflow tips
  • Workflow pitfalls
  • Appendix 1 – correlation tokens

You can download all this from http://sharepointchris.googlepages.com/COB_WorkflowResources.zip

P.S. I’ll be expanding on this content – the next couple of articles will be workflow-focused.

Introducing the SharePoint Content Deployment Wizard

Regular readers might have spotted I’ve been slightly quieter than usual over the past few weeks – actually I’ve not been slacking, but working on a tool which you might find useful from time to time. As I’ve discussed in numerous posts, deployment of SharePoint artifacts is something that’s perhaps more complex than it should be, and the standard tools provided don’t always simplify this picture. Personally, over my past few MOSS projects, there have been several times when I’ve thought:

  • I just need to move this document library from A to B
  • I just need to move these selected files (e.g. master page, page layouts, CSS etc.) from A to B
  • I just need to move this web from A to B
  • I just need to move this site collection from A to B
  • I just need to move these 20 list items from A to B

If only there was an easy way! CMS 2002 users may remember the SDO export mechanism which allowed you to use a treeview to select exactly which content you wished to move, but unfortunately there’s no similar tool for MOSS. Sure, we have Content Deployment and STSADM export etc., but the lowest level of granularity is a web, and if you don’t want to overwrite the whole thing neither option can be used. The only other option is to write code which uses the Content Migration API. This is fine for projects which have the appropriate development skills and time, but otherwise things can be tricky.

Enter the SharePoint Content Deployment Wizard.

The tool provides a wizard-like approach to deploying content between SharePoint sites. The selected content is exported using the Content Migration API (PRIME), giving a .cmp file (Content Migration Package) which can be copied to other servers.

Since pictures are often more useful than words, let’s look at using the tool. Click to enlarge any of the images below:

EXPORTING CONTENT

Welcome screen (click any image to enlarge):


Select action (import or export) and provide site URL:

 

For export, use the treeview to select which content you wish to deploy. On container objects such as webs, there are options about whether descendent objects should be included:

 
Select options around security, dependencies, versions and name of the export file:
 
 
 
The details are shown back for confirmation, and when ‘Finish’ is clicked the export will begin:
 
 
 
IMPORTING CONTENT
 

Browse to the .cmp file we exported in the previous steps, and select options around security, versions and, importantly for some scenarios, whether object IDs should be retained:
 
 

The details are shown back for confirmation, and when ‘Finish’ is clicked the import will begin:
 
 
 

And that’s the gist of it. This is the first beta of the tool and I’m sure there will be issues. Regardless, when using any tool which makes this kind of change to your data you should always take a backup before performing the import. Depending on what you’re doing, it could be difficult to revert back to the previous state otherwise.

Some other notes:

  • the tool must be installed locally on the server which hosts the site
  • not all features of the Content Migration API are supported by the tool
  • the next beta (mid-December) will properly support large sites – currently the site bind operation can be slow for large sites since the treeview is built in one operation
  • it must be run under an account which has the appropriate permissions to the SharePoint site – use the Windows ‘Run as..’ feature to do this if necessary (shown below in the image below- right-click on the .exe and select ‘Run as..’)

 
In the next post, I’ll cover details on different usages of the tool and the effect of different options. The tool also supports reparenting (e.g. importing a web or list to a different parent on the target) and I’ll talk about this.

You can download the tool now from www.codeplex.com/SPDeploymentWizard. All feedback (particularly bug reports) welcome, either post here or on the Codeplex site.

Change a SharePoint site’s URL

Something you may find yourself tasked with at some point, is changing the URL of an existing SharePoint 2007 site. This is a fairly interesting scenario, and it’s fair to say the relationship between SharePoint and IIS makes this more complex than for a standard .Net site. However, there are several possible solutions. The first things many of us would think of as potential approaches would probably be:

  • extending the web application onto another URL
  • using Alternate Access Mappings somehow

Depending on your site both could be valid methods, but as with anything SharePoint-related, there are different things to watch out for with the different approaches. As an example, extending the web application wasn’t the right approach for our scenario for the following reasons:

  • the site shouldn’t actually exist at the old URL, but a redirect was required
  • InfoPath forms don’t seem to deal well with the ‘extended web application’ configuration. (Problem detail – on one URL everything will be fine, but if the two web applications use separate site collections, on the other you’re likely to see security errors when opening forms. This is because the form templates are referenced in the other site collection – a document library can only have one URL to the document template, and publishing a form to a content type stores an absolute link in the content database.)

Additionally some quick tests with Alternate Access Mappings didn’t seem to give the expected results for me, so I decided on another approach since I knew it would work and didn’t have much time for experimentation. So this was my process:

Changing a site’s URL by recreating the site (downtime required)

  1. Stop old IIS site.
  2. Create new web application in SharePoint, bind to new IP address in IIS.
  3. Apply SSL certificate if appropriate.
  4. Create new site collection for this web application using the blank site template.
  5. Export content using the SharePoint’s content migration API (I have a tool which does this, which will shortly be on Codeplex) ensuring all security data is exported. Alternatives to this step include STSADM -O BACKUP and STSADM-O EXPORT. *
  6. Import content into the new site collection, ensuring to include security.
  7. Amend any absolute URLs in .udcx data connection files used by InfoPath.
  8. Republish any InfoPath forms to the new site.
  9. Configure search:
    1. Ensure new URL is a content source.
    2. Update any crawl rules which use absolute URLs.
    3. Update ‘authoritative pages’ as appropriate.
    4. Start full crawl.
    5. Update scopes.
    6. Go to Site Settings > Site collection administration > Search scopes, add any custom scopes to search dropdown (if using standard search web parts).
    7. Ensure search web parts use relative URLs/do not reference old site URLs.
  10. If a redirect from old URL is required, create new IIS site to implement this:
    1. Create new site in IIS and bind to old IP address.
    2. On ‘Home directory’ tab, specify content should come from ‘A redirection to a URL’ and enter the URL.
  11. Ensure DNS/firewalls are configured appropriately for new URL, remembering to allow appropriate time for DNS propagation.
  12. Perform testing.

* N.B. Between the content migration API and STSADM export, I prefer the former since this allows control over whether object GUIDs are retained (more information in STSADM export, Content Deployment, Content Migration API, Features/Solutions – deployment options compared). STSADM backup/restore is discussed in next section.

Considerations to this approach

  • When using the content migration API or STSADM backup/restore, the following items are not included – alerts, workflows, recycle bin state or site collection properties. These must be migrated/recreated separately.
  • Regression testing is absolutely required since the site is effectively recreated

As a way to improve on the first consideration, another option would be STSADM backup/restore (though I’ve not tried this approach). Notably this method does collect data for the items which the other approaches exclude, however due to the nature of our site, none of these were significant problems.

So this method was successful, and hopefully this information allows folks to see some of the pros and cons without having to spend the time going through it themselves. However, I also note an approach based on Alternate Access Mappings suggested by Faraz Khan. Since this was only published in the few days before this article it was too late for my scenario, though I’d encourage you to take a look. Note that Faraz also points out considerations such as certain links not being updated to new URL without fix-ups, though this doesn’t seem to be a major issue. It does echo my point about there being different things to watch out for with the different approaches, but both methods provide valid techniques for changing a SharePoint site’s URL.