Dear Constant Reader (or at least, one-blog-per-day-until-Christmas-day-5 reader),
As it's almost beer-o-clock here in the office, and I need to make sure I get to the beer table first so as not to miss out on the chippies, today's blog post is incredibly short and equally as incredibly obvious! It's also the first in the continuing series of "Code Snippets" along with all the other continuing series I seem to have started this week. Doh!
The Scenario/Challenge
Often when working in a feature receiver we need to get the current SPWeb in context – i.e. the site the feature was activated on.
Now as an aside, those young players amongst you will be quick to shout out, "ooh – SPContext.Current.Web"! And that may well work when you activate the feature from the browser, but will fail epicly when a feature is stapled or activated by STSADM and there's no SPContext.
The correct way to do this is to use the SPFeatureReceiverProperties object passed in to the feature. But still, it's possible to screw this up. Let's say your feature is "Web" scoped, then you could be forgiven for writing the following:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb site = (SPWeb)properties.Feature.Parent;
}
Looks pretty good, but let's say you suddenly decide to change your feature to "Site" scope. This code will then fail epicly, since .Parent will then become an SPSite, and you'll get a nice casting exception (similar to the casting exception that should have been thrown when Temuera Morrison auditioned for Star Wars, but I digress...) So ideally, you want to be inspecting the type of object before you go about casting it.
The Solution
Here's a nicely encapsulated extension method that we can throw in a feature to grab the contextual SPWeb, whether site or web-scoped. This is really trivial... but useful since I don't like writing more code than I have to, and often get the scoping wrong to begin with.
public static SPWeb GetWeb(this SPFeatureReceiverProperties properties)
{
SPWeb site;
if (properties.Feature.Parent is SPWeb)
{
site = (SPWeb) properties.Feature.Parent;
}
else if (properties.Feature.Parent is SPSite)
{
site = ((SPSite)properties.Feature.Parent).RootWeb;
}
else
{
throw new Exception("Error 192424234223442: Unable to retrieve SPWeb - this feature is not Site or Web-scoped.");
}
return site;
}
And here's our nice single LOC that uses this in our feature receiver:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = properties.GetWeb();
}
Though... you might actually want to do something else in your method :)
Argh! The chippies are disappearing! Catchya tomorrow (and I promise the code will be more interesting next week!)
:) Matt