When applying a workflow to a business process, a common requirement will be to change the list item’s permissions at different stages of the workflow – such as various approval statuses. While this seems straightforward enough, with the obvious solution to have the workflow set the item’s permissions so, for example:
- The user responsible for sending the item for approval can edit the item prior to sending for approval.
- Once the item is sent for approval, only approvers can edit the item.
- Once approved, no-one can edit the item except for admins/owners.
This works well with small lists, however once the number of items in the list reaches about 2000, your entire SharePoint farm will start to run into performance issues. The problem relates to the number of security scopes in the list. Each list item with fine-grained permissions adds one security scope to the list, and each scope adds more SQL queries and fetches more data which will soon overwhelm your database server.. lagging the entire farm!
More details about fine-grained permission limits:
So what is the solution to this problem? Well, there isn’t one… The TechNet white paper linked above hints at a workaround to control edit permissions using the SPEventReceiverType.ItemUpdating and SPEventReceiverType.ItemUpdated methods, creating your own security layer based off the item’s metadata.
So lets try it.
In this case we are checking “Status” field and then allowing or cancelling the event based off this value. Create an event handler and override ItemUpdating to do something based on the status…
public override void ItemUpdating(SPItemEventProperties properties)
if ((properties.ListItem.FileSystemObjectType != SPFileSystemObjectType.Folder))
case "Waiting for review":
case "Waiting for approval":
If the item’s “Status” is “Approved”, only admins and Owners can perform the edit…
public void CheckApproved(SPItemEventProperties properties)
SPWeb web = properties.Web;
SPGroup ownerGroup = web.AssociatedOwnerGroup;
bool inGroup = web.IsCurrentUserMemberOfGroup(ownerGroup.ID);
bool siteAdmin = web.UserIsSiteAdmin;
bool webAdmin = web.UserIsWebAdmin;
if (!inGroup && !siteAdmin && !webAdmin)
properties.RedirectUrl = properties.WebUrl + "/documents/noedit.aspx";
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
If the action is cancelled a page is displayed in a pop-up.