Question

I've got a situation where there are strict permissions requirements on an a list of which I already have written a custom form. The requirement is that upon creation, based on metadata, only certain users have access to read and write the item.

My first attempt at this was to put this in an event receiver on the list to make sure the permissions get updated at when the item is added. I put the item in the item added event since during item adding I don't have a way to elevate privileges and get an elevated instance of the item (that I know of). This caused an unwanted delay, though short, between the time the item was created and the time the code actually ran.

The next thing I tried was to put set the item permissions in the form immediately after the item is created since I would then have an ID for the item so I can retrieve it in an elevated context (I want the item to be created under the context of the current user). This is problematic because as soon as this approach was implemented, about 50% of the time we get an error in a workflow that runs on item create saying: “Failed to start workflow. The workflow cannot access the item that is has been applied to.” (It's probably worth noting this is a Nintex workflow) - I assume the problem is due to some race condition where in the middle of the item.Update() to set the permissions, the workflow tries to start at the same time.

Ideally I would like to be able to update permissions on the very first item update (create) or during an ItemAdding event, but I am not sure how to do this without elevating the whole process such that the item is then created by the system account and not the user who actually created the item.

What options do I have available to me?

Was it helpful?

Solution

The way you originally had it using the ItemAdded event was correct. There is just one step missing though - you can make the event run immediately by changing it to run synchronously instead of asynchronously.

Details of how to switch the synchronous mode are here: http://blogs.technet.com/b/stefan_gossner/archive/2011/11/10/using-synchronous-quot-after-quot-events-e-g-itemupdated-in-sharepoint-2010.aspx

OTHER TIPS

One approach you could try, is enabling content approval on that list. This will mean, that whenever a new item is created, it will remain in Pending status until it is approved. When an item is in Pending status, only the originator of the item and the people who have permissions to manage lists and libraries can see it, provided you chose the following setting: Who should see draft items in this document library? -> Only users who can approve items (and the author of the item). Then, you could use the ItemAdded event to change the permissions of the file and also put in the Approved state.

I hope this helps you out in your particular scenario.

You should be able to impersonate the user that created the item or made the change in your code.

    public override void ItemUpdating(SPItemEventProperties properties)     
       {     
           base.ItemUpdating(properties);

           SPUserToken objSPUserToken = properties.OriginatingUserToken;

           if (objSPUserToken != null) 
           { 
               using (SPSite objSPSite = new SPSite(properties.SiteId, objSPUserToken)) 
               { 
                   using (SPWeb objSPWeb = objSPSite.OpenWeb())

                   { 
                       //You can perform user context specific changes here... 
                   } 
               } 
           }
       }

Impersonation Elevation of Privileges

Event Impersonation in SharePoint 2010

What I've done to get around this issue is to instead of automatically start the workflow via the settings of the workflow, we are "manually" kicking off the workflow via code after permissions are updated.

string workflowId = "{...}"; //dynamically retrieve workflow id
SPWorkflowManager workflowManager = item.Web.Site.WorkflowManager;
SPWorkflowAssociationCollection workflowCollection = item.ParentList.WorkflowAssociations;

foreach (SPWorkflowAssociation workflow in workflowCollection)
{
    if (String.Compare(workflow.BaseId.ToString("B"), workflowId, true) == 0)
    {
        workflowManager.StartWorkflow(item, workflow, workflow.AssociationData, true);
        break;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top