Logo Home   Downloads   Up to Bluedog Limited
SharePoint Thoughts
A blog centered on Windows® SharePoint® Services
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:
Posted by Maurice Prather
A fairly common question that I receive is why do solution packages have the .wsp extension when in fact they are cab files... and does it matter if you leave the extension as .cab?
 
Why wsp as new extension?  Maybe because .wsp is nice way to differentiate solution files and maybe because there are some long term plans that center on solution file types.  For the time being this is really design preference.
 
The answer for the "can i just leave them as .cab files" is Yes.  There is nothing in the framework that prevents you from naming your files whatever you want with whatever extension you want. 
 
For all our deployments, my team exclusively uses .cab for all solution (and web part) packages.  How many times have you seen someone rename a .wsp file to .cab just to look at the contents, then rename it (then perhaps getting the rename out of sync with the original wsp name)?  Since there is no technical reason to not leave the extension as .cab, why even name the files with the .wsp extension?  Bottom line it makes life much easier leaving the extension as .cab makes it super easy to utilize Window's built-in handler for cab files. 
 
Cab on!
 
-Maurice
 
Posted @ 2:12 PM on Monday, July 07, 2008 | Comments:

(Items 1 to 5)Next
Keyword Search
 
View by category
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.