Jun 25 2009

SharePoint Site Settings Custom Actions Feature

I just released the third Feature that is now part of the Trentacular SharePoint 2007 Features CodePlex project: Site Settings Custom Actions

The Feature currently adds just a single custom action and page for exposing and managing Web (Site) properties with a similar UI as the previously released Farm Properties Editor (part of the Central Administration Extensions Feature).

Manage Farm Properties

The Web Properties Editor has proved convenient for externalizing site-specific configuration settings from which your custom features, whatever they may be, can read from. It also abstracts away the peculiarities of the SPWeb.Properties and SPWeb.AllProperties API which I wrote about in my last post – a must read if you are a SharePoint developer and haven’t already.


Jun 25 2009

SharePoint: The Wicked SPWeb.Properties PropertyBag

*** This article is a must read for any developer reading or writing Web (Site) properties ***

If you haven’t already noticed, there are two different API properties on the SPWeb class – AllProperties (a Hashtable) and Properties (a PropertyBag). Apparently the AllProperties is meant to replace Properties, but Properties was left in place for backwards compatibility. Here’s where things get wicked …

The unconventional PropertyBag data type stores its keys in all lowercase, thus not supporting case-sensitive keys, while the conventional Hashtable does support case-sensitive keys. On top of that, while entries added to Properties get propagated to AllProperties with a lowercase key, entries added to AllProperties do not get propagated to Properties. So this what Microsoft gives us developer peons to work with. This is why consultants like myself stay employed.

If you are working with property entries that only your custom application will be reading and writing from, simply always use AllProperties and you will be good to go. However I often find myself having to work with properties that are read or written by SharePoint internals, and SharePoint itself is very inconsistent in its interaction with Web (Site) properties, probably due to its evolving nature being a rather old product as far as software is concerned.

So the best solution that I have come up with to date is to add your entries to both API properties. This ensures the entry will be present in both collections, and also ensures the key will have the correct case in AllProperties. I have found though in order to add to both, the order of the update API calls is important – you must first update the SPWeb object followed by updating the SPWeb.Properties PropertyBag. Performing the updates in the reverse order prevents an entry with a case-sensitive key from being added to AllProperties, and only the lowercase-keyed entry will be exposed in AllProperties. Now that you are probably thoroughly confused, here is the code:

// Add a property entry
web.Properties[key] = value;
web.AllProperties[key] = value;
web.Update();
web.Properties.Update();
 
// Remove a property entry
web.AllProperties.Remove(key);
web.Properties[key] = null;
web.Update();
web.Properties.Update();

Take a look, or straight up copy, my SharePoint utility class that abstracts away Web property interactions.


Jun 11 2009

SharePoint Central Administration Extensions Feature

I just released the second feature that is now part of the Trentacular SharePoint 2007 Features CodePlex project: Central Administration Extensions

The solution currently deploys just a single custom action and page for managing farm properties. This has proved useful for us as a means to centralize configuration that is applicable across our entire SharePoint farm, such as custom application connection strings, log4net config file location, etc.

If you are a seasoned ASP.Net developer, you may also find the included Delegate Data Source useful. It essentially exposes the 4 main data source methods (select, insert, update, and delete) as events that can be handled directly in your code behind.


Jun 11 2009

SharePoint: Differences Between Global and Web Application Targeted Solution Deployment

SharePoint solutions are either deployed globally or targeted to a particular web application.  The decision of which is made automatically by the SharePoint Solution framework depending on the contents of the solution manifest.  Certain items in the solution manifest such as SafeControl entries result in modifications to a Web application’s web.config file.  Only when a solution manifest does NOT contain any of these types of entries will the solution be globally deployed.

The deployment process behaves differently based on the type of deployment for the solution, and these differences have caused me quite a headache. Here are my findings that I think any SharePoint developer or administrator should be aware of when performing solution deployments.

Globally Deployed Solutions

When a solution is deployed globally, all SharePoint application pools, including Central Administration’s, are recycled automatically. This can be good and bad. This is good because any GAC installed DLL that has been upgraded needs to be reloaded. This can be bad though with regards to the availability of your entire SharePoint Farm.

In my particular case, I am working with a SharePoint administrator to deploy a globally deployed solution that is used by only a single web application. It is fine for this web application to be unavailable, as we have cleared it with our change control process and made announcements of the downtime, but we haven’t announced to users of the other SharePoint web applications in the Farm that their sites will be coming down along with it. So be forwarned.

Web Application Targeted Solutions

I have become fond of web application targeted solutions because they offer me a workaround to the above availability problem.  When a web application targeted solution is deployed or retracted, only the application pools of the targeted web applications are recycled.

Enterprise Farm Strategies

  • When upgrading solutions, the upgradesolution stsadm command only gets you so far. I’ve found it is best to fully retract and remove the old solution and then add and deploy the new solution in order to be sure your upgraded features actually take.
  • Avoid the -allcontenturls switch – When deploying and retracting a web application targeted solution, deploy or retract it only to those web applications that will use it … thus preventing unnecessary recycling of application pools. I was being lazy in my retraction script and instead of specifying the particular web application url, I used the -allcontenturls switch to retract my solution, hoping SharePoint would be smart enough to recycle only the application pools of the web applications the solution was actually retracted from. Bad assumption. They all get recycled.

A Big Gotcha that Got Me

If you are upgrading a web application targeted solution using the retract, remove, add, deploy strategy mentioned above and your web application scoped Features have associated Feature Receivers, then you must recycle the Central Administration application pool after removing the old solution and before adding the new solution if you intend to use the Central Admin Web application features page to activate your solution’s Features.  In this case, it is the Central Administration application pool that executes your web application scoped Feature Receivers, and if not recycled, it will continue to use the loaded cached old versions of assemblies updated by your solution.

The same also goes for powershell.  If within a powershell console you deactivate a Feature having a Feature receiver, the assembly containing the Feature receiver will be loaded and cached by the powershell App domain.  After retracting, removing, adding, and redeploying the solution in the same powershell console, it will still be the previous version of the assembly that is cached.  If you were to attempt to script the activation of your Feature, your updated Feature receiver’s code is never executed, rather the previous version from the cached assembly is used.  To get around this dilemma, you can either increment your assembly version or start a new powershell console before deploying and activating your updated solution’s Features.