I no longer work at Microsoft, so please don't bother leaving a comment here or trying to contact me through my MSDN blog.
You can find my new blog at http://www.technologytoolbox.com/blog/jjameson. My new site also provides copies of all posts from my MSDN blog.
In my previous post (Scope Dependencies for SharePoint Features) you may have noticed that in the Feature.xml file, I specified the feature receiver class as DefaultFeatureReceiver but the code sample is actually from FeatureConfigurator. This warrants a little explanation.
In order to simplify the development and debugging of feature receivers, I find it much easier to put the bulk of the code in a FeatureConfigurator class and then have the DefaultFeatureReceiver class simply be a "thin shell" that utilizes the underlying FeatureConfigurator class to do the bulk of the work:
namespace Fabrikam.Project1.PublicationLibrary.Configuration { [CLSCompliant(false)] public class DefaultFeatureReceiver : SPFeatureReceiver { [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)] public override void FeatureActivated( SPFeatureReceiverProperties properties) { if (properties == null) { throw new ArgumentNullException("properties"); } SPWebApplication webApp = properties.Feature.Parent as SPWebApplication; if (webApp == null) { throw new InvalidOperationException( "The feature must be activated at the 'WebApplication' scope."); } FeatureConfigurator.Configure(webApp); } ... } }
The bulk of the development (and debugging) of the feature receiver is then performed using a separate Visual Studio test project:
namespace Fabrikam.Project1.PublicationLibrary.DeveloperTests.Configuration { [TestClass()] public class FeatureConfiguratorTest { ... [TestMethod()] public void ConfigureTest() { string project1Url = Properties.Settings.Default.Project1Url; Uri webAppUri = new Uri(project1Url); SPWebApplication webApp = SPWebApplication.Lookup(webAppUri); FeatureConfigurator.Configure(webApp); // If we make it to here without an exception, then all is well Assert.IsTrue(true); } } }