Logo Home   Downloads   Up to Bluedog Limited
SharePoint Thoughts
A blog centered on Windows® SharePoint® Services
Posted by Maurice Prather

Impersonation is an interesting topic.  It has many uses and I've widely discussed this topic over the years. 

Here's what you need to know in a simple boiled down outline...

  • Direct impersonation and/or the direct use of RevertToSelf is unsupported.  Direct impersonation is the action where you change the identity in line X, and on line X+1 you execute an action using the same objects where were previously available before you changed the user identity or the altered identity code section executes within the same process space. 
  • In v2, the only way to circumvent the issue of direct circumvention was to use "heavy" methods such as COM+ and the AppDomain Interface Loader techniques.
  • In v3, the SharePoint OM now offers a helper method RunWithElevatedPriviledges that *mostly* eliminates the need to use the heavy methods.  RWEP is fairly effective in allowing you to complete what you need to accomplish, but there are some weird failures have been noticed.  This is probably related to the fact that RWEP under the hood has a lot of things to manage to change the context from User to System.
  • In v3, you still have the option of using the traditional heavy methods.  The COM+ and AppDomain Interface Loader methods can effectively bypass any issues faced with RWEP.  With the traditional methods, you have absolutely removed yourself from the HTTP context and your code is in effective no different than a standard console application. 

If you look at the first bullet point, something very important should be jumping out at you by now...

No matter which methodology you decide to use, it is important to break context before executing code using the new identity.  This effectively means that you can't utilize an SP* object that was created in one identity and expect that same object to work in the altered user context.  The process of creating new objects is critical to your code's success.

In other words, if you take an SP* object that was created as part of the current request and attempt to use it in altered context, you run the risk of your code not working (and you could argue is still within the realm of an unsupported action).

It's good to point out that the hidden advantage of the AppDomain technique was that it forced you to create new objects because most of SharePoint's object could not be marshaled between application domains.  Therefore, a developer was always forced to save the "simplest" types needed to get the job done before running their privileged code.  In other words, you probably ended up saving information such as user id, login names, site and web ids, list item ids as nothing more than basic types so that the privileged methods could receive the marshaled data and subsequently create the necessary SharePoint objects to execute the desired actions.

Let's take a look at some code to highlight the differences in object usage...

Problematic code:

// Grab a reference to the context-specific web..
SPWeb web = SPContent.Current.Web;

SPSecurity.RunWithElevatedPrivileges (delegate () {
  
  // There is one major problem here: this code is using objects created under a 
  // different user identity.  This may or may not work.
  
  web.Title = "A new title";
  web.Update();
  
});

The correct approach:

// Store the necessary information...
Guid siteID = SPContext.Current.Site.ID;
Guid webID  = SPContent.Current.Web.ID;

SPSecurity.RunWithElevatedPriveleges (delegate () {
  
  // Now create new objects with the information previously stored. This ensures
  // the SP* objects are created with the correct identity association.

  using (SPSite site = new SPSite (siteID))
  using (SPWeb web = site.OpenWeb(webID)) {
    web.Title = "A new title";
    web.Update();
  }
  
});

Bottom line: When changing the running identity, you must create your own objects to effectively break the context between the different identities.

Best Practices SharePoint Conference
I will be co-presenting on this very topic at the Best Practices SharePoint Conference next week.  If you are attending the conference, please swing by and check out the presentation and let's talk about the subtleties of the different impersonation techniques.  :)

References:
Advanced coding technique: using AppDomains to get past OM limitations
Q&A on the interface loader technique and AppDomains
SPSecurity.RunWithElevatedPrivileges Method (Microsoft.SharePoint)

Posted @ 9:28 AM on Friday, September 12, 2008 | Comments:
Posted by Maurice Prather
It's worth noting a few problems have been encountered with recently released Infrastructure Update.
  • In the custom code category, it appears a deep level fix/change within the request lifecycle has changed the availability of the SPContext.Current object.  If you've written code that deals with the IHttpHandlerFactory, your code will no longer work as it was originally designed.  Dan Larson has a code snippet that outlines the problem.
  • In the administrative category, the associated WSS KB article now includes a footnote about an Alternate Access Mapping regression.  AAM, with the IU in place, is defaulting to the wrong url and therefore your system will become unresponsive.

For most folks, the SPContext issue may have no bearing on your deployments if you are running a standard OOB.  The problem lies with custom code that you've written and/or installed.  It's worth checking.

The AAM issue could be a big show stopper.  Again, it's worth checking your farm configuration to determine how, if at all, you rely on AAM.

As always, it's important to test your deployments in a development/staging environment before rolling out new hotfixes and service packs (the UI is a technically a hot fix, btw). 

-Maurice

Posted @ 1:46 PM on Tuesday, July 29, 2008 | Comments:
Posted by Maurice Prather
Awhile ago, I was conversing with someone about the features of the newer .Net Framework versions.  One of the features mentioned was generics.  My friend mentioned that he really liked the concept and recently started using them, but that he still couldn't quite see how generic collections could really be put to work.  Ok... so that's the lead in for today's post - generics, collections, and 1 more "new" feature called anonymous methods. 
 
For starters, f you haven't looked at generics, shame on you.  That is some seriously wicked stuff that will do nothing but help you in the long run.  If you haven't checked out generic collections, that's ok... I think a lot of folks haven't really touched on that area because so much legacy code relies on the old way of working with collections.  Anyways, if you need some help with generics and generic collections, open up a new browser session and read up on the topics. 
 
First, let's dive into how generic collections can be utilized...
 
Everyone's probably really familiar with writing a recursive algorithm.  It's a dev 101 type of thing to learn and use.  Some of the most common recursive methods are those used to find information that is buried in a tree of some sort (e.g. looking for a specific Control on your page, etc.). For example, a method to find a specific Control would look something like...
 
    public Control FindControlOnPage (Control control, string targetID) { 
      
      Control current = control; 
      
      if (current.ID == targetID) {
        return current; 
      }
      
      foreach (Control c in current.Controls) {

        Control found = FindControlOnPage (c, targetID);
        
        if (found != null) {
          return found;
        }
        
      }
      
      return null;
      
    }   // End of FindControlOnPage
 
Unfortunately, recursive algorithms can be hard to follow and/or debug.  Especially if your algorithm is fairly complex or the tree is pretty large.
 
With generic collections, you have an opportunity to replace a traditional recursive method with a Stack collection.  For example...
 
    public Control FindControlUsingStack (Control rootControl, string targetID) { 
      
      // Initialize the stack...
      Stack<Control> stack = new Stack<Control> ();
      
      // Seed the stack...
      stack.Push(rootControl);
      
      // Work with the stack until it's empty...
      while (stack.Count != 0) {
        
        // Take a control off the top of the stack...
        Control current = stack.Pop ();
        
        // Determine if this is the target control...
        if (current.ID == targetID) {
          return current;
        }
        
        // Add child controls to the stack...
        foreach (Control c in current.Controls) {
          stack.Push(c);
        }
        
      }
      
    }   // End of FindControlUsingStack
 
As you can see, generic collections make it possible to do things a little differently. It's not to say this is the best (or worst) way to search for a control.  Nor does the example code account for errors or circular references. The best part of this methodology (at least for me) is the simple fact that the code has a very inline feel and the debugging experience is much kinder.
 
What about anonymous methods?
Delegates are nothing more than method signatures. In older versions of the .Net Framework, delegates could only be used in named methods.  In the C# 2.0, you now have the ability to simply instantiate a delegate and specify a code block that the delegate will immediately process when it's called.  A lot of people are probably familiar with using the RunWithElevatedPrivileges method with an anonymous method as shown belowe (example taken from the MSDN reference page):
 
     SPSecurity.RunWithElevatedPrivileges(delegate()
     {
         using (SPSite site = new SPSite(web.Site.ID))
         {
         // implementation details omitted
         }
     });
 
Anonymous methods are super handy... so let's roll all of this information into a handy SharePoint routine!
 
Let's setup a few design points for our scenario...
  • Create a method that executes a method on all sub-sites of a SharePoint site but doesn't execute that method on the parent site
  • It doesn't use traditional recursion
  • It doesn't use the AllWebs property
 
To solve this problem,
  1. Define a delegate that takes a SPWebCollection object and
  2. Create stack-based "recursion" method.
Your library code will look like...
 
  public class Utility {

    /// <summary>
    /// Delegate that takes an SPWeb object as its only parameter
    /// </summary>
    public delegate void CodeToExecute (SPWeb web);
    
    private Utility () {
      // Do nothing, other than hide the default constructor
    }  // End of constructor
        
    /// <summary>
    /// Execute a method against all children of the specified web
    /// </summary>
    public static void ExecuteRecursively (SPWeb web, CodeToExecute code) {
      
      // Initialize the stack...
      Stack<SPWebCollection> stack = new Stack<SPWebCollection>();
      
      // Seed the stack...
      stack.Push(web.Webs);
      
      // Work with the stack until it's empty...
      while (stack.Count != 0) {
        
        foreach (SPWeb w in stack.Pop()) {
         
          // Add w's child webs to the stack...
          stack.Push(w.Webs);
          
          // Execute the desired method against the current web w...
          code(w);
          
        }
        
      }
      
    }  // End of ExecuteRecursively
    
  }  // End of Utility class

 
Your utility class is complete. Now it's time to use it!
 
The "ExecuteRecursively" method can be called using an anonymous method or the good old-fashioned way of a named method. Here's a call with an anonymous delegate...
 
      Utility.ExecuteRecursively (this.Web, delegate(SPWeb w) {
        
        // Check to see if the web does not inherit permissions...
        if (w.HasUniqueRoleAssignments) { 
          
          // If unique, add/remove user...
          w.RoleAssignments.Remove(w.CurrentUser);
          
        }
        
      } );
 
Note how you can easily reference the active SPWeb w in the anonymous method. The delegate definition allows you pass in a web, from which you can reference within your anonymous method.
 
Wth the utility class in hand, it's super easy to write a "recursive" method in practically no time flat. The key advantages to using this methodology is speed and, once again, ease of debugging.
 
Finally, keep in mind the ExecuteRecursively method is slightly different than the FindControlUsingStack method shown earlier. The utility class was designed to operate on the children of the starting point, not the starting point itself (like in the FindControlUsingStack example). Within the utility class, you can incorporate logic that best suites your needs (for example, perhaps you want to test if a SPWeb object is of a particular type before running the code) and starting points.
 
Cool, eh? Happy coding!
-Maurice
Posted @ 11:31 PM on Sunday, July 20, 2008 | Comments:
Posted by Maurice Prather
Earlier today, the SharePoint team released the Infrastructure Update for both Windows SharePoint Services and Office Server.  The release is something more than Service Pack, more than a Feature Pack, more than rollup of hotfixes... it's a fairly comprehensive set of improvements in feature functionality and performance characteristics.
 
The 64-bit downloads are available at...

http://www.microsoft.com/downloads/details.aspx?FamilyID=3a74e566-cb4a-4db9-851c-e3fbbe5e6d6e&DisplayLang=en

http://www.microsoft.com/downloads/details.aspx?FamilyID=6e4f31ab-af25-47df-9bf1-423e248fa6fc&DisplayLang=en

The ECM blog was the first to publically announce the release... the SharePoint team blog will probably have more info by the end of the day... and the accompanying KB articles will probably also come online shortly.

UPDATE 7/15 @ 1400 pst: The SharePoint Team Blog announcement has finally gone live.

Exciting stuff!
-Maurice

Posted @ 2:28 PM on Tuesday, July 15, 2008 | Comments:
Posted by Maurice Prather
Recently, I was involved in an interesting conversation with some folks.  The conversation actions that were considered unsupported in v2 and how (or if) they apply to v3.
 
For example...
  • Direct database queries
  • Adding web parts to Form pages
  • Directly calling the OM with an altered identity (using Impersonation or Revert-to-self methodologies)

In general if an action was called out as unsupported in v2, chances are the action will remain unsupported in v3.  Unless MSFT has explicitly come out with a recategorization of support or a feature add/replacement, the original v2 statement of no support stands. 

Ideally, the "Applies To" section of the relevant KB articles will be updated with the appropriate information but there's a chance the information will not be updated in a timely fashion.  (note: this is true for most any product out there today.  as recently as last week, i found a weird characteristic in Excel.  after 10 minutes of research, i found a kb article that covered the issue and was originally written against XL2000.  It was never updated to cover all versions since the original release but the behavior is still evident Office 2007.)

I believe it's important to note the product history so that you don't accidentally stumble into an unsupported region.  All too many times nowadays, I come across recommendations and articles advocating a variety of unsupported actions.  Therefore, it's definitely getting harder for the average reader to discern between ideas and methodologies that follow the supported path or branch off into uncharted territories.

Of course, the funniest arguments of why something "should" work come from those folks that argue "if the OM can do it, so can I".   That is not a sound argument and you shouldn't fall victim to that reasoning.  If that were the case, the first item in the bulleted list above would immediately fall off and you wouldn't have the folks like myself, Keith Richie, Joel Oleson, Mike Fitzmaurice, et.al. always saying "stay out of the database".

-Maurice

p.s. for those that have noticed in the past, yes - my New Comments pages had non-default web parts.  Yes, that is technically an unsupported page.  It took me way too long to get it working (it wasn't a simple drag/drop operation as with other web part pages) and the failures encountered were exactly why web parts on form pages are still considered unsupported.  it was created as a proof of concept piece and to illustrate the potential difficulty with that scenario...

Posted @ 12:02 PM on Tuesday, July 15, 2008 | Comments:

(Items 1 to 5)Next
Keyword Search
 
View by category

 MVP Logo

MVP Logo
Looking for a team of experts to help with <companyProject type="businessCritical"/>? 
 
My team at ShareSquared can help ... drop us a note.
 
 
ShareSquared, Inc.
 
Subscribe with Bloglines
Microsoft Certified Professional Logo

Disclaimer:
The contents of this site represent thoughts and opinions of the authors , not those of anyone else - such as past, present and future employers.  This a forum of the exchange of ideas centered on SharePoint technologies.  It is not a support channel.  :)

Copyright © 2004-2008 BluedogLimited.com. All rights reserved.