Using SPSite and SPWeb objects with RunWithElevatedPrivileges: Don’t cross the borders

This blog post is a contribution from David Wilborn, an engineer with the SharePoint Developer Support team.

Although it’s mentioned in the SPSecurity.RunWithElevatedPrivileges documentation, I find that there is still often a lack of clarity for developers when using SPSite and SPWeb objects in conjunction with RunWithElevatedPrivileges delegate.

The mistake I see the most often is attempting to get an SPSite or SPWeb object with elevated privileges by initializing the object inside of a RunWithElevatedPrivileges delegate, then using the object outside of the delegate:

 SPSite elevatedSite = null;
 SPSecurity.RunWithElevatedPrivileges(delegate()
 {
     // BAD: This object will not correctly retain elevated status outside of the delegate!
     badElevatedSite = new SPSite("https://mysharepointsite"); 
 });
 SPWeb web = badElevatedSite.RootWeb; // Will not have desired permissions

Another common issue is using an already initialized SPSite or SPWeb inside of a RunWithElevatedPrivileges delegate and assuming its permissions will be elevated:

 SPSite site = new SPSite("https://mysharepointsite");
 SPSecurity.RunWithElevatedPrivileges(delegate()
 {
     // This SPWeb will NOT have elevated privileges, because "site" does not
     SPWeb notElevatedWeb = site.RootWeb; 
 });

An SPSite and SPWeb object initialized inside of a RunWithElevatedPrivileges block will have indeterminate permissions when used outside of that block – in other words, sometimes the object will retain the elevated privileges and sometimes it will not.  I’ve seen cases where a customer’s code written this way will work fine for months on end, then suddenly stop working when no code has changed!

So what’s the correct way to create SPSite and SPWeb objects with elevated privileges?  Always create and dispose off the objects within the RunWithElevatedPrivileges delegate.  Instead of elevating an existing object’s permissions, you’ll need to create a new object:

 SPSite site = new SPSite("https://mysharepointsite");
 // additional code using the site object
 SPSecurity.RunWithElevatedPrivileges(delegate()
 {
     // Create a new elevated version of the same site collection object
     using (SPSite elevatedSite = new SPSite(site.Id))    
     {
         SPWeb elevatedWeb = elevatedSite.RootWeb;
         // perform elevated operations with elevatedWeb here. . .
     } // SPSite object gets disposed automatically
 });

A simple rule of thumb is don’t “cross the border” with your SPSite and SPWeb objects – don’t use an object created outside of the RunWithElevatedPrivileges delegate within the delegate, and dispose all SPSite and SPWeb objects created within the delegate before the delegate completes.