Sep
2
2009
I just released a new stsadm command in the Trentacular SharePoint 2007 Features CodePlex project called smartsolutionupgrade. The purpose of this command is to perform Solution upgrades in a smart manner by performing the following actions:
- Accepts as input either a single Solution filename or a filename of a text file containing a list of Solutions to be upgraded
- Extracts and parses the Solution manifest file from each existing Solution to be upgraded in order to determine the Features that will be affected by the upgrade
- Inventories the deployment states of the existing Solutions
- Inventories the activation states of the affected Features at all scopes within the SharePoint Farm
- Deactivates all affected Features
- Retracts each of the existing Solutions and deletes them from the Solution store
- Adds the updated Solution to the Solution store
- Deploys each of the upgraded Solutions according to their previous deployment state
- Activates all affected Features according to their previous activation state
Usage
stsadm -o smartsolutionupgrade [-filename <Solution filename>] [-filenamelist <Path to text file containing each of the solution filenames on separate lines>]
Job Definition Execution
Included in the project is a Job Definition Executor that takes care of running one-time scheduled service jobs and waiting for their completion before releasing control. One particular issue addressed by the Job Definition Executor is the “A web configuration modification operation is already running” error caused by successive execution of the stsadm -o activatefeature command on Features that perform web configuration modifications.
In a multi-server farm, web configuration modifications are delegated to Timer Jobs; therefore, the return from execution of the activatefeature command does not mean the Feature activation (and thus the web configuration modification) has completed. So you might say, well duh, you need to also execute the execadmsvcjobs command, but this command simply kicks of the job execution and returns from execution while still not waiting for the jobs to actually complete.
The Job Definition Executor solves this problem by kicking of the jobs and monitoring for their completion. We can now safely execute multiple web configuration modification Features in sequence.
Update
I just released a second stsadm command called smartexecjobdefs that simply wraps the Job Definition Executor and can be used as a substitute for the execadmsvcjobs command.
11 comments | tags: feature, moss, sharepoint, smartsolutionupgrade, solution, solution deployment, stsadm, wsp, wss | posted in sharepoint
Jun
25
2009
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).

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.
no comments | tags: custom action, feature, sharepoint, site settings | posted in sharepoint
Jun
11
2009
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.
no comments | tags: central admin, feature, sharepoint | posted in sharepoint
May
22
2009
I’ve finally gotten around to starting a CodePlex project for publishing SharePoint features called Trentacular SharePoint 2007 Features. The first contribution to the project should reach a broad audience (within the SharePoint population that is) … an ASP.Net 3.5 Upgrade Feature.
The Feature is naturally scoped to a Web Application and adds ASP.Net 3.5 entries to the particular Web Application’s web.config file. It works for both WSS and MOSS and also supports clean deactivation by iterating through the SPWebConfigModification collection and removing modifications by owner instead of recreating the modifications. All modifications are done through a utility class called SPWebConfigModificationHelper which can be taken advantage of alone if you are writing your own modifications.
Before deciding to write this feature, I tried several others that have been published. Each had its own issues, from not supporting clean deactivation to simply just not adding the correct entries. The entries this feature writes were taken from the Visual Studio ASP.Net 3.5 Web.config template.
If you give this Feature a shot, please let me know how it goes.
2 comments | tags: asp.net 3.5, feature, moss, sharepoint, wss | posted in sharepoint
Apr
14
2009
Greg Galipeau wrote a thorough post on cleaning up your Web Part Gallery that is the basis for this post. To summarize, Greg shares a Feature Receiver he uses as a generic Feature Receiver for all his WebPart Features that simply removes the WebPart having the same name as the Feature’s DisplayName when the Feature is deactivated.
There are a couple of issues with this though:
- It assumes that the WebPart has the same name as the Feature
- It limits the Feature to deploying just a single WebPart
An alternative approach would be to inspect the Feature’s element definitions and extract the exact WebPart names that were deployed, thus resolving the two issues noted above.
Below is the alternative Feature Receiver (it extends the BaseFeatureReceiver I mentioned in my previous post):
public class WebPartFeatureReceiver : BaseFeatureReceiver<SPSite>
{
public override void FeatureDeactivating(SPSite site, SPFeatureReceiverProperties properties)
{
base.FeatureDeactivating(site, properties);
var elements = properties.Definition.GetElementDefinitions(CultureInfo.CurrentCulture);
var webparts = elements.Cast<SPElementDefinition>()
.SelectMany(e => e.XmlDefinition.ChildNodes.Cast<XmlElement>()
.Where(n => n.Name.Equals("File"))
.Select(n => n.Attributes["Url"].Value)
)
.ToList();
var rootWeb = site.RootWeb;
var wpGallery = rootWeb.Lists["Web Part Gallery"];
var galleryItems = wpGallery.Items.Cast<SPListItem>()
.Where(li => webparts.Contains(li.File.Name))
.ToList();
for (int i = galleryItems.Count - 1; i >= 0; i--)
{
var item = galleryItems[i];
item.Delete();
}
}
}
5 comments | tags: API, feature, feature receiver, sharepoint, webpart | posted in sharepoint
Apr
14
2009
If you are writing SharePoint feature receivers often, you will find there are several lines of code common to just about every feature receiver:
- A cast of properties.Feature.Parent to the appropriate scope (either SPWeb, SPSite, SPWebApplication, or SPFarm)
- Empty implementations of FeatureInstalled and FeatureUninstalling
Provided below is an abstract generic class that now serves as the base class for every feature receiver I write. It eliminates the redundant code by performing the cast for you based on the classes generic type parameter and also goes ahead and implements all the abstract methods, making it so that you to only need to override the actual methods you plan to handle. Your extending feature receiver now will look like the following:
public class MyFeatureReceiver : BaseFeatureReceiver<SPWeb>
{
public override void FeatureDeactivating(SPWeb scope, SPFeatureReceiverProperties properties)
{
// Pointless, but what the heck
base.FeatureDeactivating(scope, properties);
// Now do something with your scope object, in this case an SPWeb
...
}
}
And now, the code for the BaseFeatureReceiver:
/// <summary>
/// Base class that makes the feature scope available as an argument to the
/// FeatureActivated and FeatureDeactivating methods
/// </summary>
/// <typeparam name="T">
/// T is the class type of the scope of the feature (SPFarm, SPWebApplication, SPSite, or SPWeb)
/// </typeparam>
public abstract class BaseFeatureReceiver<T> : SPFeatureReceiver
{
public sealed override void FeatureActivated(SPFeatureReceiverProperties properties)
{
FeatureActivated((T)properties.Feature.Parent, properties);
}
public virtual void FeatureActivated(T scope, SPFeatureReceiverProperties properties) { }
public sealed override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
FeatureDeactivating((T)properties.Feature.Parent, properties);
}
public virtual void FeatureDeactivating(T scope, SPFeatureReceiverProperties properties) { }
public override void FeatureInstalled(SPFeatureReceiverProperties properties) { }
public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }
}
Hope you find this helpful.
4 comments | tags: API, feature, feature receiver, generics, sharepoint | posted in sharepoint
Recent Comments