locked
Setting Item Level Permissions in ItemUpdated Event Handler giving error. RRS feed

  • Question

  • Hi SP Experts,

    Problem Statement:

    I have document library with unique permissions [Team Owners and Team Members] groups. I can upload 2 types of document in this library [private and public]. these types are nothing but document library column "Doc_Classification".

    If user uploads document with its classification set to private, Item level permissions are breaked [Itm.Breakroleinheritance(false)] and two groups i.e. [Team Owners and Memebrs] are assinged to it.

    If user uploads document with its classification set to public, Item level permissions are breaked [Itm.Breakroleinheritance(false)] and three groups i.e. [Team Owners,Memebrs and Readers] are assinged to it. [Here assume all the groups are present at site collection level]

    I have used "ItemUpdated" event handler to capture these events and have checked if Doc_Classification is "Private" or "Public" and based on that called BreakItemPermissions() function  for 2[owner and member group as parameter for private doc ] or 3 [owner, member and reader group as parameter for public doc ]times based on classification.

    Issues:

    1. This function works properly for administrator user and gives access denied error for users from member and owner group

       -- i have used RunWithElevatedPermissions in this function still giving this issue

     

    2. When i debug this event handler there are two threads which executes simulteneously one behind the other i.e. if i have 3 break points in my code and if first thread is at brk point#31 another thread starts at brk point #1.

     --  not sure why there are two threads here

     

     Sample Code:

    in Event handler in ItemUpdated()

    if (properties.ListItem[Doc_Classification] == "Private")

    {

    BreakItemPermissions(properties,Permission_Level,"Team Owner");

    BreakItemPermissions(properties,Permission_Level,"Team Member");

    }

    if (properties.ListItem[Doc_Classification] == "Public")

    {

    BreakItemPermissions(properties,Permission_Level,"Team Owner");

    BreakItemPermissions(properties,Permission_Level,"Team Member");

    BreakItemPermissions(properties,Permission_Level,"Team Reader");

     

    In function

    BreakItemPermission();

    {

    SPweb web = properties.web;

    web.Allowunsafeupdates = true;

    properties.ListItem.BrakRoleInheritance(false);

    roledefination ...

    roleassignment....

    web.Allowunsafeupdates = false;

    }

     

    Please suggest!!! Many thanks in advance

    Regards,

    Ketan Gandhi



    • Edited by SPGeek003 Wednesday, January 11, 2012 3:29 PM
    Wednesday, January 11, 2012 3:27 PM

Answers

  • About part two...

     

    The event you are using (ItemUpdated) is fired AFTER the change has been done.

    For this reason the AfterProperties are useless for any changes.

    My answer was more oriented to the problem of setting your status column... don't try to use the properties.listitem, but try to:

    1. either load item from list , based on your current context - where SPWeb web = properties.Web - based on code from my former reply (logic identical to the other poster's)

    2. create new SPWeb object with "fresh" context, by code again equal to the above poster's:

    SPSite freshSite = new SPSite(properties.SiteId)); //we are opening same thing, but in fresh context
    SPWeb freshWeb =  tempSite.OpenWeb(properties.RelativeWebUrl); 
    freshWeb.AllowUnsafeUpdates = true;
    
    //the rest of this is identical as in approach 1, since only difference is fetching the item from NEW web context
    
    SPList tempList = freshWeb.Lists[properties.ListId]; //don't forget to read from "fresh" SPWeb
    SPListItem tempItem = tempList.GetItemByID(properties.ListItemId); //you now have "clear" item, that shouldn't raise any conflicts
    tempItem["Doc_Status"] = "Approve";
    tempItem.UpdateOverwriteVersion();
    
    freshWeb.AllowUnsafeUpdates = false;
    freshWeb.Dispose(); //don't forget to dispose
    freshSite.Dispose();
    


     

    • Marked as answer by Pengyu Zhao Wednesday, January 18, 2012 6:20 AM
    Thursday, January 12, 2012 12:19 PM

All replies

  • Hello!

    Please, show how do you use RunWithElevatedPermissions? You have to create new SPSite and SPWeb objects inside RunWithElevatedPermissions. You have to extract SPList and SPListItem from the SPSite and SPWeb objects created inside RunWithElevatedPermissions. It should be something like the following:

    SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (var spSite = new SPSite(properties.SiteId))
                    {
                        using (var spWeb = spSite.OpenWeb(properties.RelativeWebUrl))
                        {
                            var spList = spWeb.Lists[properties.ListId];
                            var spListItem = spList.GetItemById(properties.ListItemId);
    
                            // actions with spListItem
                        }
                    }
                });
    .Net Follower (http://dotnetfollower.com)


    Wednesday, January 11, 2012 3:41 PM
  • Hi,

    Many thanks for your response.

    Breaking permissions seems to be working, however one basic functionality before breaking permissions is not working.

    Here what i am trying to do is there are 2 columns Doc_Classification and Doc_Status. when document is uploaded as "Public" i.e Doc_Classification is public andf my code needs to automatically set its status to "Approve".

    so what i am doing is in ItemUpdated event of document library.

    this.EventFiringEnabled = false;

    web.allowunsafeupdates=true;

    If(properties.ListItem[Doc_Classification].ToString() == "Public")

    {

    properties.ListItem[Doc_Status] = "Approve";

    properties.ListItem.UpdateOverwriteVersion();

    }

    web.allowunsafeupdates = false;

    this.EventFiringEnabled = true;

     

    I am not able to update the list items another field [Doc_Status].

     

    Please suggest.

    Regards,

    Ketan Gandhi

    Thursday, January 12, 2012 9:14 AM
  • It gives me following error.

    Save Conflict.

    your changes conflict with those made concurrently by another user.If you want your changes to be applied,, click Back in your

    Web Browser, refresh the page, and resubmit your changes.

    Please Suggest !!!!

    Regards,

    Ketan

     

    Thursday, January 12, 2012 9:33 AM
  • Try not to use the list item from context, but rather (re)load new item object as the .Net Follower mentioned in the post above.

    Eg.

    SPList tempList = web.Lists[properties.ListId];
    SPListItem tempItem = tempList.GetItemByID(properties.ListItemId);
    tempItem["Doc_Status"] = "Approve";
    tempItem.UpdateOverwriteVersion();
    


    This should solve your save conflict.

    Worst case scenario... create fresh SPWeb object (again, similar as in previous poster's sample, use run under elevated permissions if you expect insufficient ) and retrieve list and item from it, and don't forget to dispose it. SharePoint is vulnerable to dirty context scenarios, so creating fresh SPWeb (and SPSite from which it derives) usually does the trick.


    Thursday, January 12, 2012 10:10 AM
  • Hi Ferovac,

     

    Many thanks for your response.

    There are two issues over here:

    1. breaking item permissions, which i am doing it with runwithelevatedpermissions....so in this context what you and.net folower is saying is right...lets park this issue for time being.

    2.  forget about breaking item permissions i need to set one fields value based on other...like id Doc_classification is public then in ItemUpdated event i need to set Doc_Status = "Approve". thats it. for doing this simple thing it is giving save conflict error.

    also while setting status columns value should i use properties.listitem["Doc_Status"] or properties.AfetrProperties.listItem["Doc_status"]????

    Please advice

    Regards,

    Ketan

    Thursday, January 12, 2012 11:39 AM
  • About part two...

     

    The event you are using (ItemUpdated) is fired AFTER the change has been done.

    For this reason the AfterProperties are useless for any changes.

    My answer was more oriented to the problem of setting your status column... don't try to use the properties.listitem, but try to:

    1. either load item from list , based on your current context - where SPWeb web = properties.Web - based on code from my former reply (logic identical to the other poster's)

    2. create new SPWeb object with "fresh" context, by code again equal to the above poster's:

    SPSite freshSite = new SPSite(properties.SiteId)); //we are opening same thing, but in fresh context
    SPWeb freshWeb =  tempSite.OpenWeb(properties.RelativeWebUrl); 
    freshWeb.AllowUnsafeUpdates = true;
    
    //the rest of this is identical as in approach 1, since only difference is fetching the item from NEW web context
    
    SPList tempList = freshWeb.Lists[properties.ListId]; //don't forget to read from "fresh" SPWeb
    SPListItem tempItem = tempList.GetItemByID(properties.ListItemId); //you now have "clear" item, that shouldn't raise any conflicts
    tempItem["Doc_Status"] = "Approve";
    tempItem.UpdateOverwriteVersion();
    
    freshWeb.AllowUnsafeUpdates = false;
    freshWeb.Dispose(); //don't forget to dispose
    freshSite.Dispose();
    


     

    • Marked as answer by Pengyu Zhao Wednesday, January 18, 2012 6:20 AM
    Thursday, January 12, 2012 12:19 PM